Preprocessing in python: briefly I normalised and log transformed the raw counts data, filtered for celltypes/conditions of interest and export the normalised counts as csv (same as cellphoneDB), also export metadata for cell type (level_3_annot).

Install CellChat (https://github.com/sqjin/CellChat)

#devtools::install_github("jokergoo/ComplexHeatmap")
#devtools::install_github("jokergoo/circlize")
#devtools::install_github("sqjin/CellChat")

Install other dependencies

#install.packages('NMF')

Load required libraries

library(CellChat)
library(patchwork)
library(Seurat)
library(SeuratObject)
library(plyr)
options(stringsAsFactors = FALSE)

library(NMF)
library(dplyr)
#library(sceasy)
library(igraph)
library(Matrix)
library(ggplot2)
library(ggalluvial)
library(circlize)

Load input data and meta data

data <- read.table(file = '/nfs/team205/ao15/Megagut/Annotations_v3/disease_analysis/interactions/counts/pooled_disease.remapped.allgenes.AP_SI.counts.csv', header = T, row.names=1, sep=",", as.is=T)
head(data[,1:10])
meta <- read.csv(file = '/nfs/team205/ao15/Megagut/Annotations_v3/disease_analysis/interactions/meta/pooled_disease.remapped.allgenes.AP_SI.meta.csv', header = T, row.names=1,sep=",", as.is=T)
head(data[,1:10])
head(meta)
#to make the barcodes in counts consistent, for some reason the barcodes that read "AACCGCGCAGTTTACG-HCA_A_GT12934998" are being changed to "AACCGCGCAGTTTACG.HCA_A_GT12934998"
colnames(data) = gsub('[.]', '-', colnames(data))
#head(data[,1:10])

#quickly list barcodes by transposing dataframe
#data_t <- t(data)
#row.names(data_t)
head(data[,1:10])

Make seurat object from csv

srat <- CreateSeuratObject(data, project = "MUC6", assay = "RNA", min.cells = 0, min.features = 0, meta.data = meta)

From here the script follows the CellChat tutorial

data.input <- srat@assays$RNA@counts

cell.use = rownames(meta)

Create a cellchat object:

cellchat <- createCellChat(object = data.input, meta = meta, group.by = "level_3_annot")
Create a CellChat object from a data matrix
Set cell identities for the new CellChat object
The cell groups used for CellChat analysis are  B_GC_I B_GC_II B_memory B_naive B_plasma_IgA1 B_plasma_IgA2 B_plasma_IgG B_plasma_IgM B_plasmablast BEST4_enterocyte_colonocyte Crypt_fibroblast_PI16 DC_cDC1 DC_cDC2 DC_langerhans DC_migratory DC_pDC EC_arterial_1 EC_arterial_2 EC_capillary EC_cycling EC_lymphatic EC_venous Enterocyte Enteroendocrine Eosinophil/basophil Epithelial_stem Erythrocytes Fibroblast_reticular Follicular_DC gdT gdT_naive Glial_1 Glial_2 Glial/Enteric_neural_crest Goblet Goblet_cycling Goblet_progenitor ILC3 Immune_recruiting_pericyte Lamina_propria_fibroblast_ADAMDEC1 Macrophage Macrophage_LYVE1 Macrophage_MMP9 Macrophage_TREM2 MAIT Mast Microfold Monocyte Mucous_gland_neck Myofibroblast Neuroblast NK_CD16 NK_CD56bright Oesophagus_fibroblast Oral_mucosa_fibroblast Paneth Pericyte Rectum_fibroblast Surface_foveolar T/NK_cycling TA Tfh Tfh_naive Tnaive/cm_CD4 Tnaive/cm_CD8 Treg Treg_IL10 Trm_CD4 Trm_CD8 Trm_Th17 Trm/em_CD8 Tuft Vascular_smooth_muscle Villus_fibroblast_F3 
cellchat <- addMeta(cellchat, meta = meta)
cellchat <- setIdent(cellchat, ident.use = "level_3_annot") # set "labels" as default cell identity
levels(cellchat@idents) # show factor levels of the cell labels
 [1] "B_GC_I"                             "B_GC_II"                           
 [3] "B_memory"                           "B_naive"                           
 [5] "B_plasma_IgA1"                      "B_plasma_IgA2"                     
 [7] "B_plasma_IgG"                       "B_plasma_IgM"                      
 [9] "B_plasmablast"                      "BEST4_enterocyte_colonocyte"       
[11] "Crypt_fibroblast_PI16"              "DC_cDC1"                           
[13] "DC_cDC2"                            "DC_langerhans"                     
[15] "DC_migratory"                       "DC_pDC"                            
[17] "EC_arterial_1"                      "EC_arterial_2"                     
[19] "EC_capillary"                       "EC_cycling"                        
[21] "EC_lymphatic"                       "EC_venous"                         
[23] "Enterocyte"                         "Enteroendocrine"                   
[25] "Eosinophil/basophil"                "Epithelial_stem"                   
[27] "Erythrocytes"                       "Fibroblast_reticular"              
[29] "Follicular_DC"                      "gdT"                               
[31] "gdT_naive"                          "Glial_1"                           
[33] "Glial_2"                            "Glial/Enteric_neural_crest"        
[35] "Goblet"                             "Goblet_cycling"                    
[37] "Goblet_progenitor"                  "ILC3"                              
[39] "Immune_recruiting_pericyte"         "Lamina_propria_fibroblast_ADAMDEC1"
[41] "Macrophage"                         "Macrophage_LYVE1"                  
[43] "Macrophage_MMP9"                    "Macrophage_TREM2"                  
[45] "MAIT"                               "Mast"                              
[47] "Microfold"                          "Monocyte"                          
[49] "Mucous_gland_neck"                  "Myofibroblast"                     
[51] "Neuroblast"                         "NK_CD16"                           
[53] "NK_CD56bright"                      "Oesophagus_fibroblast"             
[55] "Oral_mucosa_fibroblast"             "Paneth"                            
[57] "Pericyte"                           "Rectum_fibroblast"                 
[59] "Surface_foveolar"                   "T/NK_cycling"                      
[61] "TA"                                 "Tfh"                               
[63] "Tfh_naive"                          "Tnaive/cm_CD4"                     
[65] "Tnaive/cm_CD8"                      "Treg"                              
[67] "Treg_IL10"                          "Trm_CD4"                           
[69] "Trm_CD8"                            "Trm_Th17"                          
[71] "Trm/em_CD8"                         "Tuft"                              
[73] "Vascular_smooth_muscle"             "Villus_fibroblast_F3"              
groupSize <- as.numeric(table(cellchat@idents)) # number of cells in each cell group
CellChatDB <- CellChatDB.human # use CellChatDB.mouse if running on mouse data
showDatabaseCategory(CellChatDB)

# Show the structure of the database
dplyr::glimpse(CellChatDB$interaction)
Registered S3 method overwritten by 'cli':
  method     from         
  print.boxx spatstat.geom
Rows: 1,939
Columns: 11
$ interaction_name   <chr> "TGFB1_TGFBR1_TGFBR2", "TGFB2_TGFBR1_TGFBR2", "TGFB3_TGFBR1_TGFBR2", "TGFB1…
$ pathway_name       <chr> "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TG…
$ ligand             <chr> "TGFB1", "TGFB2", "TGFB3", "TGFB1", "TGFB1", "TGFB2", "TGFB2", "TGFB3", "TG…
$ receptor           <chr> "TGFbR1_R2", "TGFbR1_R2", "TGFbR1_R2", "ACVR1B_TGFbR2", "ACVR1C_TGFbR2", "A…
$ agonist            <chr> "TGFb agonist", "TGFb agonist", "TGFb agonist", "TGFb agonist", "TGFb agoni…
$ antagonist         <chr> "TGFb antagonist", "TGFb antagonist", "TGFb antagonist", "TGFb antagonist",…
$ co_A_receptor      <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",…
$ co_I_receptor      <chr> "TGFb inhibition receptor", "TGFb inhibition receptor", "TGFb inhibition re…
$ evidence           <chr> "KEGG: hsa04350", "KEGG: hsa04350", "KEGG: hsa04350", "PMID: 27449815", "PM…
$ annotation         <chr> "Secreted Signaling", "Secreted Signaling", "Secreted Signaling", "Secreted…
$ interaction_name_2 <chr> "TGFB1 - (TGFBR1+TGFBR2)", "TGFB2 - (TGFBR1+TGFBR2)", "TGFB3 - (TGFBR1+TGFB…
#> Rows: 1,939
#> Columns: 11
#> $ interaction_name   <chr> "TGFB1_TGFBR1_TGFBR2", "TGFB2_TGFBR1_TGFBR2", "TGF…
#> $ pathway_name       <chr> "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "T…
#> $ ligand             <chr> "TGFB1", "TGFB2", "TGFB3", "TGFB1", "TGFB1", "TGFB…
#> $ receptor           <chr> "TGFbR1_R2", "TGFbR1_R2", "TGFbR1_R2", "ACVR1B_TGF…
#> $ agonist            <chr> "TGFb agonist", "TGFb agonist", "TGFb agonist", "T…
#> $ antagonist         <chr> "TGFb antagonist", "TGFb antagonist", "TGFb antago…
#> $ co_A_receptor      <chr> "", "", "", "", "", "", "", "", "", "", "", "", ""…
#> $ co_I_receptor      <chr> "TGFb inhibition receptor", "TGFb inhibition recep…
#> $ evidence           <chr> "KEGG: hsa04350", "KEGG: hsa04350", "KEGG: hsa0435…
#> $ annotation         <chr> "Secreted Signaling", "Secreted Signaling", "Secre…
#> $ interaction_name_2 <chr> "TGFB1 - (TGFBR1+TGFBR2)", "TGFB2 - (TGFBR1+TGFBR2…

# use a subset of CellChatDB for cell-cell communication analysis
#CellChatDB.use <- subsetDB(CellChatDB, search = "Secreted Signaling") # use Secreted Signaling
# use all CellChatDB for cell-cell communication analysis
CellChatDB.use <- CellChatDB # simply use the default CellChatDB

# set the used database in the object
cellchat@DB <- CellChatDB.use
cellchat <- subsetData(cellchat) # subset the expression data of signaling genes for saving computation cost
future::plan("multiprocess", workers = 4) # do parallel
Strategy 'multiprocess' is deprecated in future (>= 1.20.0). Instead, explicitly specify either 'multisession' or 'multicore'. In the current R session, 'multiprocess' equals 'multisession'.[ONE-TIME WARNING] Forked processing ('multicore') is not supported when running R from RStudio because it is considered unstable. For more details, how to control forked processing or not, and how to silence this warning in future R sessions, see ?parallelly::supportsMulticore
cellchat <- identifyOverExpressedGenes(cellchat)
cellchat <- identifyOverExpressedInteractions(cellchat)
cellchat <- projectData(cellchat, PPI.human)
#note trim is referring to Cellchats method for calculating the truncated mean, default is 0.25 meaning expression will be set to 0 if 25% or less of cells of a given cell type express the ligand/receptor. By default, I've changed this to 10% to account for genes expressed in a small portion of cells, that could still be biologically relevant. I beleive this is more similar to CellphoneDB cut offs anyway.

cellchat <- computeCommunProb(cellchat, raw.use = TRUE, type = "truncatedMean", trim = 0.1)

  |                                                                                                                                                           
  |                                                                                                                                                     |   0%
  |                                                                                                                                                           
  |=                                                                                                                                                    |   0%
  |                                                                                                                                                           
  |=                                                                                                                                                    |   1%
  |                                                                                                                                                           
  |==                                                                                                                                                   |   1%
  |                                                                                                                                                           
  |==                                                                                                                                                   |   2%
  |                                                                                                                                                           
  |===                                                                                                                                                  |   2%
  |                                                                                                                                                           
  |====                                                                                                                                                 |   2%
  |                                                                                                                                                           
  |====                                                                                                                                                 |   3%
  |                                                                                                                                                           
  |=====                                                                                                                                                |   3%
  |                                                                                                                                                           
  |=====                                                                                                                                                |   4%
  |                                                                                                                                                           
  |======                                                                                                                                               |   4%
  |                                                                                                                                                           
  |=======                                                                                                                                              |   4%
  |                                                                                                                                                           
  |=======                                                                                                                                              |   5%
  |                                                                                                                                                           
  |========                                                                                                                                             |   5%
  |                                                                                                                                                           
  |========                                                                                                                                             |   6%
  |                                                                                                                                                           
  |=========                                                                                                                                            |   6%
  |                                                                                                                                                           
  |==========                                                                                                                                           |   6%
  |                                                                                                                                                           
  |==========                                                                                                                                           |   7%
  |                                                                                                                                                           
  |===========                                                                                                                                          |   7%
  |                                                                                                                                                           
  |===========                                                                                                                                          |   8%
  |                                                                                                                                                           
  |============                                                                                                                                         |   8%
  |                                                                                                                                                           
  |=============                                                                                                                                        |   8%
  |                                                                                                                                                           
  |=============                                                                                                                                        |   9%
  |                                                                                                                                                           
  |==============                                                                                                                                       |   9%
  |                                                                                                                                                           
  |==============                                                                                                                                       |  10%
  |                                                                                                                                                           
  |===============                                                                                                                                      |  10%
  |                                                                                                                                                           
  |================                                                                                                                                     |  10%
  |                                                                                                                                                           
  |================                                                                                                                                     |  11%
  |                                                                                                                                                           
  |=================                                                                                                                                    |  11%
  |                                                                                                                                                           
  |=================                                                                                                                                    |  12%
  |                                                                                                                                                           
  |==================                                                                                                                                   |  12%
  |                                                                                                                                                           
  |===================                                                                                                                                  |  12%
  |                                                                                                                                                           
  |===================                                                                                                                                  |  13%
  |                                                                                                                                                           
  |====================                                                                                                                                 |  13%
  |                                                                                                                                                           
  |====================                                                                                                                                 |  14%
  |                                                                                                                                                           
  |=====================                                                                                                                                |  14%
  |                                                                                                                                                           
  |======================                                                                                                                               |  14%
  |                                                                                                                                                           
  |======================                                                                                                                               |  15%
  |                                                                                                                                                           
  |=======================                                                                                                                              |  15%
  |                                                                                                                                                           
  |=======================                                                                                                                              |  16%
  |                                                                                                                                                           
  |========================                                                                                                                             |  16%
  |                                                                                                                                                           
  |=========================                                                                                                                            |  16%
  |                                                                                                                                                           
  |=========================                                                                                                                            |  17%
  |                                                                                                                                                           
  |==========================                                                                                                                           |  17%
  |                                                                                                                                                           
  |==========================                                                                                                                           |  18%
  |                                                                                                                                                           
  |===========================                                                                                                                          |  18%
  |                                                                                                                                                           
  |============================                                                                                                                         |  18%
  |                                                                                                                                                           
  |============================                                                                                                                         |  19%
  |                                                                                                                                                           
  |=============================                                                                                                                        |  19%
  |                                                                                                                                                           
  |=============================                                                                                                                        |  20%
  |                                                                                                                                                           
  |==============================                                                                                                                       |  20%
  |                                                                                                                                                           
  |===============================                                                                                                                      |  20%
  |                                                                                                                                                           
  |===============================                                                                                                                      |  21%
  |                                                                                                                                                           
  |================================                                                                                                                     |  21%
  |                                                                                                                                                           
  |================================                                                                                                                     |  22%
  |                                                                                                                                                           
  |=================================                                                                                                                    |  22%
  |                                                                                                                                                           
  |==================================                                                                                                                   |  22%
  |                                                                                                                                                           
  |==================================                                                                                                                   |  23%
  |                                                                                                                                                           
  |===================================                                                                                                                  |  23%
  |                                                                                                                                                           
  |===================================                                                                                                                  |  24%
  |                                                                                                                                                           
  |====================================                                                                                                                 |  24%
  |                                                                                                                                                           
  |=====================================                                                                                                                |  24%
  |                                                                                                                                                           
  |=====================================                                                                                                                |  25%
  |                                                                                                                                                           
  |======================================                                                                                                               |  25%
  |                                                                                                                                                           
  |======================================                                                                                                               |  26%
  |                                                                                                                                                           
  |=======================================                                                                                                              |  26%
  |                                                                                                                                                           
  |=======================================                                                                                                              |  27%
  |                                                                                                                                                           
  |========================================                                                                                                             |  27%
  |                                                                                                                                                           
  |=========================================                                                                                                            |  27%
  |                                                                                                                                                           
  |=========================================                                                                                                            |  28%
  |                                                                                                                                                           
  |==========================================                                                                                                           |  28%
  |                                                                                                                                                           
  |==========================================                                                                                                           |  29%
  |                                                                                                                                                           
  |===========================================                                                                                                          |  29%
  |                                                                                                                                                           
  |============================================                                                                                                         |  29%
  |                                                                                                                                                           
  |============================================                                                                                                         |  30%
  |                                                                                                                                                           
  |=============================================                                                                                                        |  30%
  |                                                                                                                                                           
  |=============================================                                                                                                        |  31%
  |                                                                                                                                                           
  |==============================================                                                                                                       |  31%
  |                                                                                                                                                           
  |===============================================                                                                                                      |  31%
  |                                                                                                                                                           
  |===============================================                                                                                                      |  32%
  |                                                                                                                                                           
  |================================================                                                                                                     |  32%
  |                                                                                                                                                           
  |================================================                                                                                                     |  33%
  |                                                                                                                                                           
  |=================================================                                                                                                    |  33%
  |                                                                                                                                                           
  |==================================================                                                                                                   |  33%
  |                                                                                                                                                           
  |==================================================                                                                                                   |  34%
  |                                                                                                                                                           
  |===================================================                                                                                                  |  34%
  |                                                                                                                                                           
  |===================================================                                                                                                  |  35%
  |                                                                                                                                                           
  |====================================================                                                                                                 |  35%
  |                                                                                                                                                           
  |=====================================================                                                                                                |  35%
  |                                                                                                                                                           
  |=====================================================                                                                                                |  36%
  |                                                                                                                                                           
  |======================================================                                                                                               |  36%
  |                                                                                                                                                           
  |======================================================                                                                                               |  37%
  |                                                                                                                                                           
  |=======================================================                                                                                              |  37%
  |                                                                                                                                                           
  |========================================================                                                                                             |  37%
  |                                                                                                                                                           
  |========================================================                                                                                             |  38%
  |                                                                                                                                                           
  |=========================================================                                                                                            |  38%
  |                                                                                                                                                           
  |=========================================================                                                                                            |  39%
  |                                                                                                                                                           
  |==========================================================                                                                                           |  39%
  |                                                                                                                                                           
  |===========================================================                                                                                          |  39%
  |                                                                                                                                                           
  |===========================================================                                                                                          |  40%
  |                                                                                                                                                           
  |============================================================                                                                                         |  40%
  |                                                                                                                                                           
  |============================================================                                                                                         |  41%
  |                                                                                                                                                           
  |=============================================================                                                                                        |  41%
  |                                                                                                                                                           
  |==============================================================                                                                                       |  41%
  |                                                                                                                                                           
  |==============================================================                                                                                       |  42%
  |                                                                                                                                                           
  |===============================================================                                                                                      |  42%
  |                                                                                                                                                           
  |===============================================================                                                                                      |  43%
  |                                                                                                                                                           
  |================================================================                                                                                     |  43%
  |                                                                                                                                                           
  |=================================================================                                                                                    |  43%
  |                                                                                                                                                           
  |=================================================================                                                                                    |  44%
  |                                                                                                                                                           
  |==================================================================                                                                                   |  44%
  |                                                                                                                                                           
  |==================================================================                                                                                   |  45%
  |                                                                                                                                                           
  |===================================================================                                                                                  |  45%
  |                                                                                                                                                           
  |====================================================================                                                                                 |  45%
  |                                                                                                                                                           
  |====================================================================                                                                                 |  46%
  |                                                                                                                                                           
  |=====================================================================                                                                                |  46%
  |                                                                                                                                                           
  |=====================================================================                                                                                |  47%
  |                                                                                                                                                           
  |======================================================================                                                                               |  47%
  |                                                                                                                                                           
  |=======================================================================                                                                              |  47%
  |                                                                                                                                                           
  |=======================================================================                                                                              |  48%
  |                                                                                                                                                           
  |========================================================================                                                                             |  48%
  |                                                                                                                                                           
  |========================================================================                                                                             |  49%
  |                                                                                                                                                           
  |=========================================================================                                                                            |  49%
  |                                                                                                                                                           
  |==========================================================================                                                                           |  49%
  |                                                                                                                                                           
  |==========================================================================                                                                           |  50%
  |                                                                                                                                                           
  |===========================================================================                                                                          |  50%
  |                                                                                                                                                           
  |===========================================================================                                                                          |  51%
  |                                                                                                                                                           
  |============================================================================                                                                         |  51%
  |                                                                                                                                                           
  |=============================================================================                                                                        |  51%
  |                                                                                                                                                           
  |=============================================================================                                                                        |  52%
  |                                                                                                                                                           
  |==============================================================================                                                                       |  52%
  |                                                                                                                                                           
  |==============================================================================                                                                       |  53%
  |                                                                                                                                                           
  |===============================================================================                                                                      |  53%
  |                                                                                                                                                           
  |================================================================================                                                                     |  53%
  |                                                                                                                                                           
  |================================================================================                                                                     |  54%
  |                                                                                                                                                           
  |=================================================================================                                                                    |  54%
  |                                                                                                                                                           
  |=================================================================================                                                                    |  55%
  |                                                                                                                                                           
  |==================================================================================                                                                   |  55%
  |                                                                                                                                                           
  |===================================================================================                                                                  |  55%
  |                                                                                                                                                           
  |===================================================================================                                                                  |  56%
  |                                                                                                                                                           
  |====================================================================================                                                                 |  56%
  |                                                                                                                                                           
  |====================================================================================                                                                 |  57%
  |                                                                                                                                                           
  |=====================================================================================                                                                |  57%
  |                                                                                                                                                           
  |======================================================================================                                                               |  57%
  |                                                                                                                                                           
  |======================================================================================                                                               |  58%
  |                                                                                                                                                           
  |=======================================================================================                                                              |  58%
  |                                                                                                                                                           
  |=======================================================================================                                                              |  59%
  |                                                                                                                                                           
  |========================================================================================                                                             |  59%
  |                                                                                                                                                           
  |=========================================================================================                                                            |  59%
  |                                                                                                                                                           
  |=========================================================================================                                                            |  60%
  |                                                                                                                                                           
  |==========================================================================================                                                           |  60%
  |                                                                                                                                                           
  |==========================================================================================                                                           |  61%
  |                                                                                                                                                           
  |===========================================================================================                                                          |  61%
  |                                                                                                                                                           
  |============================================================================================                                                         |  61%
  |                                                                                                                                                           
  |============================================================================================                                                         |  62%
  |                                                                                                                                                           
  |=============================================================================================                                                        |  62%
  |                                                                                                                                                           
  |=============================================================================================                                                        |  63%
  |                                                                                                                                                           
  |==============================================================================================                                                       |  63%
  |                                                                                                                                                           
  |===============================================================================================                                                      |  63%
  |                                                                                                                                                           
  |===============================================================================================                                                      |  64%
  |                                                                                                                                                           
  |================================================================================================                                                     |  64%
  |                                                                                                                                                           
  |================================================================================================                                                     |  65%
  |                                                                                                                                                           
  |=================================================================================================                                                    |  65%
  |                                                                                                                                                           
  |==================================================================================================                                                   |  65%
  |                                                                                                                                                           
  |==================================================================================================                                                   |  66%
  |                                                                                                                                                           
  |===================================================================================================                                                  |  66%
  |                                                                                                                                                           
  |===================================================================================================                                                  |  67%
  |                                                                                                                                                           
  |====================================================================================================                                                 |  67%
  |                                                                                                                                                           
  |=====================================================================================================                                                |  67%
  |                                                                                                                                                           
  |=====================================================================================================                                                |  68%
  |                                                                                                                                                           
  |======================================================================================================                                               |  68%
  |                                                                                                                                                           
  |======================================================================================================                                               |  69%
  |                                                                                                                                                           
  |=======================================================================================================                                              |  69%
  |                                                                                                                                                           
  |========================================================================================================                                             |  69%
  |                                                                                                                                                           
  |========================================================================================================                                             |  70%
  |                                                                                                                                                           
  |=========================================================================================================                                            |  70%
  |                                                                                                                                                           
  |=========================================================================================================                                            |  71%
  |                                                                                                                                                           
  |==========================================================================================================                                           |  71%
  |                                                                                                                                                           
  |===========================================================================================================                                          |  71%
  |                                                                                                                                                           
  |===========================================================================================================                                          |  72%
  |                                                                                                                                                           
  |============================================================================================================                                         |  72%
  |                                                                                                                                                           
  |============================================================================================================                                         |  73%
  |                                                                                                                                                           
  |=============================================================================================================                                        |  73%
  |                                                                                                                                                           
  |==============================================================================================================                                       |  73%
  |                                                                                                                                                           
  |==============================================================================================================                                       |  74%
  |                                                                                                                                                           
  |===============================================================================================================                                      |  74%
  |                                                                                                                                                           
  |===============================================================================================================                                      |  75%
  |                                                                                                                                                           
  |================================================================================================================                                     |  75%
  |                                                                                                                                                           
  |================================================================================================================                                     |  76%
  |                                                                                                                                                           
  |=================================================================================================================                                    |  76%
  |                                                                                                                                                           
  |==================================================================================================================                                   |  76%
  |                                                                                                                                                           
  |==================================================================================================================                                   |  77%
  |                                                                                                                                                           
  |===================================================================================================================                                  |  77%
  |                                                                                                                                                           
  |===================================================================================================================                                  |  78%
  |                                                                                                                                                           
  |====================================================================================================================                                 |  78%
  |                                                                                                                                                           
  |=====================================================================================================================                                |  78%
  |                                                                                                                                                           
  |=====================================================================================================================                                |  79%
  |                                                                                                                                                           
  |======================================================================================================================                               |  79%
  |                                                                                                                                                           
  |======================================================================================================================                               |  80%
  |                                                                                                                                                           
  |=======================================================================================================================                              |  80%
  |                                                                                                                                                           
  |========================================================================================================================                             |  80%
  |                                                                                                                                                           
  |========================================================================================================================                             |  81%
  |                                                                                                                                                           
  |=========================================================================================================================                            |  81%
  |                                                                                                                                                           
  |=========================================================================================================================                            |  82%
  |                                                                                                                                                           
  |==========================================================================================================================                           |  82%
  |                                                                                                                                                           
  |===========================================================================================================================                          |  82%
  |                                                                                                                                                           
  |===========================================================================================================================                          |  83%
  |                                                                                                                                                           
  |============================================================================================================================                         |  83%
  |                                                                                                                                                           
  |============================================================================================================================                         |  84%
  |                                                                                                                                                           
  |=============================================================================================================================                        |  84%
  |                                                                                                                                                           
  |==============================================================================================================================                       |  84%
  |                                                                                                                                                           
  |==============================================================================================================================                       |  85%
  |                                                                                                                                                           
  |===============================================================================================================================                      |  85%
  |                                                                                                                                                           
  |===============================================================================================================================                      |  86%
  |                                                                                                                                                           
  |================================================================================================================================                     |  86%
  |                                                                                                                                                           
  |=================================================================================================================================                    |  86%
  |                                                                                                                                                           
  |=================================================================================================================================                    |  87%
  |                                                                                                                                                           
  |==================================================================================================================================                   |  87%
  |                                                                                                                                                           
  |==================================================================================================================================                   |  88%
  |                                                                                                                                                           
  |===================================================================================================================================                  |  88%
  |                                                                                                                                                           
  |====================================================================================================================================                 |  88%
  |                                                                                                                                                           
  |====================================================================================================================================                 |  89%
  |                                                                                                                                                           
  |=====================================================================================================================================                |  89%
  |                                                                                                                                                           
  |=====================================================================================================================================                |  90%
  |                                                                                                                                                           
  |======================================================================================================================================               |  90%
  |                                                                                                                                                           
  |=======================================================================================================================================              |  90%
  |                                                                                                                                                           
  |=======================================================================================================================================              |  91%
  |                                                                                                                                                           
  |========================================================================================================================================             |  91%
  |                                                                                                                                                           
  |========================================================================================================================================             |  92%
  |                                                                                                                                                           
  |=========================================================================================================================================            |  92%
  |                                                                                                                                                           
  |==========================================================================================================================================           |  92%
  |                                                                                                                                                           
  |==========================================================================================================================================           |  93%
  |                                                                                                                                                           
  |===========================================================================================================================================          |  93%
  |                                                                                                                                                           
  |===========================================================================================================================================          |  94%
  |                                                                                                                                                           
  |============================================================================================================================================         |  94%
  |                                                                                                                                                           
  |=============================================================================================================================================        |  94%
  |                                                                                                                                                           
  |=============================================================================================================================================        |  95%
  |                                                                                                                                                           
  |==============================================================================================================================================       |  95%
  |                                                                                                                                                           
  |==============================================================================================================================================       |  96%
  |                                                                                                                                                           
  |===============================================================================================================================================      |  96%
  |                                                                                                                                                           
  |================================================================================================================================================     |  96%
  |                                                                                                                                                           
  |================================================================================================================================================     |  97%
  |                                                                                                                                                           
  |=================================================================================================================================================    |  97%
  |                                                                                                                                                           
  |=================================================================================================================================================    |  98%
  |                                                                                                                                                           
  |==================================================================================================================================================   |  98%
  |                                                                                                                                                           
  |===================================================================================================================================================  |  98%
  |                                                                                                                                                           
  |===================================================================================================================================================  |  99%
  |                                                                                                                                                           
  |==================================================================================================================================================== |  99%
  |                                                                                                                                                           
  |==================================================================================================================================================== | 100%
  |                                                                                                                                                           
  |=====================================================================================================================================================| 100%
# Filter out the cell-cell communication if there are only few number of cells in certain cell groups
cellchat <- filterCommunication(cellchat, min.cells = 10)
The cell-cell communication related with the following cell groups are excluded due to the few number of cells:  EC_cycling Eosinophil/basophil Erythrocytes Glial_1 Immune_recruiting_pericyte Neuroblast Oesophagus_fibroblast 

Export results as a data frame

df.net <- subsetCommunication(cellchat)
head(df.net)
write.csv(df.net, "/nfs/team205/ao15/Megagut/Annotations_v3/disease_analysis/interactions/pooled_disease.remapped.allgenes.AP_SI.cellchat_output_230523.csv", row.names = TRUE)
cellchat <- computeCommunProbPathway(cellchat)
cellchat <- aggregateNet(cellchat)
groupSize <- as.numeric(table(cellchat@idents))
par(mfrow = c(1,2), xpd=TRUE)
netVisual_circle(cellchat@net$count, vertex.weight = groupSize, weight.scale = T, label.edge= F, title.name = "Number of interactions",vertex.label.cex = 0.5)

netVisual_circle(cellchat@net$weight, vertex.weight = groupSize, weight.scale = T, label.edge= F, title.name = "Interaction weights/strength", vertex.label.cex = 0.5)

# Compute the network centrality scores
cellchat <- netAnalysis_computeCentrality(cellchat, slot.name = "netP") # the slot 'netP' means the inferred intercellular communication network of signaling pathways
UNRELIABLE VALUE: One of the ‘future.apply’ iterations (‘future_sapply-1’) unexpectedly generated random numbers without declaring so. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify 'future.seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use 'future.seed = NULL', or set option 'future.rng.onMisuse' to "ignore".UNRELIABLE VALUE: One of the ‘future.apply’ iterations (‘future_sapply-2’) unexpectedly generated random numbers without declaring so. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify 'future.seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use 'future.seed = NULL', or set option 'future.rng.onMisuse' to "ignore".UNRELIABLE VALUE: One of the ‘future.apply’ iterations (‘future_sapply-3’) unexpectedly generated random numbers without declaring so. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify 'future.seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use 'future.seed = NULL', or set option 'future.rng.onMisuse' to "ignore".UNRELIABLE VALUE: One of the ‘future.apply’ iterations (‘future_sapply-4’) unexpectedly generated random numbers without declaring so. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify 'future.seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use 'future.seed = NULL', or set option 'future.rng.onMisuse' to "ignore".
# Visualize the computed centrality scores using heatmap, allowing ready identification of major signaling roles of cell groups
#netAnalysis_signalingRole_network(cellchat, signaling = pathways.show, width = 8, height = 2.5, font.size = 10)
# Signaling role analysis on the aggregated cell-cell communication network from all signaling pathways
ht1 <- netAnalysis_signalingRole_heatmap(cellchat, pattern = "outgoing", width = 5, height = 10, font.size = 3)
ht2 <- netAnalysis_signalingRole_heatmap(cellchat, pattern = "incoming", width = 5, height = 10, font.size = 3)
pdf(file ="all_genes_plots/diseaseonly/cellchat_signalling_heatmap.pdf", width = 10, height =20)
ht1 + ht2
Heatmap/annotation names are duplicated: Relative strength
dev.off()
null device 
          1 
#personally I find this plot one of the most useful to look at an overview of signaling pathways, and then use the other functions to plot them in whichever way makes sense
#save cellchat object
saveRDS(cellchat, file = "/nfs/team205/ao15/Megagut/Annotations_v3/disease_analysis/interactions/pooled_disease.remapped.allgenes.AP_SI.cellchat_object.rds")
# Signaling role analysis on the aggregated cell-cell communication network from all signaling pathways
gg1 <- netAnalysis_signalingRole_scatter(cellchat)
Signaling role analysis on the aggregated cell-cell communication network from all signaling pathways
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
levels(cellchat@idents)
 [1] "B_GC_I"                             "B_GC_II"                           
 [3] "B_memory"                           "B_naive"                           
 [5] "B_plasma_IgA1"                      "B_plasma_IgA2"                     
 [7] "B_plasma_IgG"                       "B_plasma_IgM"                      
 [9] "B_plasmablast"                      "BEST4_enterocyte_colonocyte"       
[11] "Crypt_fibroblast_PI16"              "DC_cDC1"                           
[13] "DC_cDC2"                            "DC_langerhans"                     
[15] "DC_migratory"                       "DC_pDC"                            
[17] "EC_arterial_1"                      "EC_arterial_2"                     
[19] "EC_capillary"                       "EC_cycling"                        
[21] "EC_lymphatic"                       "EC_venous"                         
[23] "Enterocyte"                         "Enteroendocrine"                   
[25] "Eosinophil/basophil"                "Epithelial_stem"                   
[27] "Erythrocytes"                       "Fibroblast_reticular"              
[29] "Follicular_DC"                      "gdT"                               
[31] "gdT_naive"                          "Glial_1"                           
[33] "Glial_2"                            "Glial/Enteric_neural_crest"        
[35] "Goblet"                             "Goblet_cycling"                    
[37] "Goblet_progenitor"                  "ILC3"                              
[39] "Immune_recruiting_pericyte"         "Lamina_propria_fibroblast_ADAMDEC1"
[41] "Macrophage"                         "Macrophage_LYVE1"                  
[43] "Macrophage_MMP9"                    "Macrophage_TREM2"                  
[45] "MAIT"                               "Mast"                              
[47] "Microfold"                          "Monocyte"                          
[49] "Mucous_gland_neck"                  "Myofibroblast"                     
[51] "Neuroblast"                         "NK_CD16"                           
[53] "NK_CD56bright"                      "Oesophagus_fibroblast"             
[55] "Oral_mucosa_fibroblast"             "Paneth"                            
[57] "Pericyte"                           "Rectum_fibroblast"                 
[59] "Surface_foveolar"                   "T/NK_cycling"                      
[61] "TA"                                 "Tfh"                               
[63] "Tfh_naive"                          "Tnaive/cm_CD4"                     
[65] "Tnaive/cm_CD8"                      "Treg"                              
[67] "Treg_IL10"                          "Trm_CD4"                           
[69] "Trm_CD8"                            "Trm_Th17"                          
[71] "Trm/em_CD8"                         "Tuft"                              
[73] "Vascular_smooth_muscle"             "Villus_fibroblast_F3"              
gg1

#this plot is helpful to look at the overall signaling roles of cell types (ie. are they mostly sending signals, receiving signals or a mixture of both)
mat <- cellchat@net$weight
par(mfrow = c(2,2), xpd=TRUE)
for (i in 1:nrow(mat)) {
  mat2 <- matrix(0, nrow = nrow(mat), ncol = ncol(mat), dimnames = dimnames(mat))
  mat2[i, ] <- mat[i, ]
  netVisual_circle(mat2, vertex.weight = groupSize, weight.scale = T, edge.weight.max = max(mat), title.name = rownames(mat)[i])
}

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

data length exceeds size of matrix

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

number of items to replace is not a multiple of replacement length

cellchat@netP$pathways
  [1] "COLLAGEN"   "MHC-I"      "MIF"        "APP"        "MHC-II"     "CLEC"       "LAMININ"    "MK"        
  [9] "CD99"       "CXCL"       "GALECTIN"   "FN1"        "CCL"        "CD45"       "SPP1"       "VISFATIN"  
 [17] "JAM"        "ITGB2"      "THBS"       "PARs"       "CD22"       "ADGRE5"     "CEACAM"     "ICAM"      
 [25] "PECAM1"     "ANGPTL"     "PTN"        "BAFF"       "NOTCH"      "TENASCIN"   "CDH"        "CDH1"      
 [33] "COMPLEMENT" "GAS"        "SELL"       "VCAM"       "VEGF"       "GUCA"       "LCK"        "GRN"       
 [41] "MPZ"        "NECTIN"     "EGF"        "DESMOSOME"  "SELE"       "CD46"       "CHEMERIN"   "EPHB"      
 [49] "THY1"       "PDGF"       "ESAM"       "TIGIT"      "CD40"       "IL16"       "ANNEXIN"    "SEMA3"     
 [57] "EDN"        "SELPLG"     "HSPG"       "ncWNT"      "FGF"        "CDH5"       "SEMA4"      "GDF"       
 [65] "EPHA"       "NRG"        "NCAM"       "CALCR"      "TNF"        "TGFb"       "PROS"       "ANGPT"     
 [73] "IGF"        "IFN-II"     "CD23"       "CD86"       "CSF"        "TWEAK"      "APRIL"      "BTLA"      
 [81] "PERIOSTIN"  "CADM"       "CD96"       "IL1"        "CD39"       "SEMA6"      "BAG"        "L1CAM"     
 [89] "CD34"       "ALCAM"      "CD6"        "IL2"        "CD70"       "PTPRM"      "RELN"       "SEMA7"     
 [97] "CD226"      "SN"         "ANXA1"      "BMP"        "OCLN"       "WNT"        "LT"         "XCR"       
[105] "OSM"        "FLT3"       "KIT"        "PVR"        "TRAIL"      "IL6"        "LIGHT"      "MADCAM"    
[113] "RANKL"      "SEMA5"      "AGRN"       "CD80"       "ACTIVIN"    "GP1BA"      "ICOS"       "LIFR"      
[121] "CSF3"       "CSPG4"      "CHAD"       "GCG"        "NRXN"       "CX3C"       "NPY"        "VEGI"      
[129] "NEGR"       "PD-L1"      "HGF"        "NT"         "IL10"       "FASLG"      "SAA"        "IL17"      
[137] "PDL2"       "OX40"       "GIPR"       "CD137"      "CLDN"       "AGT"        "NGF"       
pathways.show <- c("MHC-II") 
# Hierarchy plot
# Here we define `vertex.receive` so that the left portion of the hierarchy plot shows signaling to fibroblast and the right portion shows signaling to immune cells 
vertex.receiver = seq(4,8) # a numeric vector. 
netVisual_aggregate(cellchat, signaling = pathways.show,  vertex.receiver = vertex.receiver)
number of items to replace is not a multiple of replacement length

pathways.show <- c("CCL") 
# Heatmap
par(mfrow=c(1,1))
pdf(file ="all_genes_plots/diseaseonly/cellchat_CCLheatmap.pdf", width = 20, height =16)
netVisual_heatmap(cellchat, signaling = pathways.show, color.heatmap = "Reds",width=50,height=50,font.size=6)
Do heatmap based on a single object 
pathways.show <- c("CXCL") 
# Heatmap
par(mfrow=c(1,1))
pdf(file ="all_genes_plots/diseaseonly/cellchat_CXCLheatmap.pdf", width = 20, height =16)
netVisual_heatmap(cellchat, signaling = pathways.show, color.heatmap = "Reds",width=50,height=50,font.size=6)
Do heatmap based on a single object 
pathways.show <- c("MHC-II") 
# Heatmap
par(mfrow=c(1,1))
pdf(file ="all_genes_plots/diseaseonly/cellchat_MHCIIheatmap.pdf", width = 20, height =16)
netVisual_heatmap(cellchat, signaling = pathways.show, color.heatmap = "Reds",width=50,height=50,font.size=4)
Do heatmap based on a single object 
par(mfrow=c(1,1))
pdf(file ="all_genes_plots/diseaseonly/cellchat_CCLchord.pdf", width = 20, height =16)
netVisual_aggregate(cellchat, signaling = 'CCL', layout = "chord", remove.isolate = TRUE, scale=TRUE)
dev.off()
png 
  2 
par(mfrow=c(1,1))
pdf(file ="all_genes_plots/diseaseonly/cellchat_CXCLchord.pdf", width = 20, height =16)
netVisual_aggregate(cellchat, signaling = 'CXCL', layout = "chord", remove.isolate = TRUE, scale=TRUE)
dev.off()
png 
  2 
par(mfrow=c(1,1))
pdf(file ="all_genes_plots/diseaseonly/cellchat_MHCIIchord.pdf", width = 20, height =16)
netVisual_aggregate(cellchat, signaling = 'MHC-II', layout = "chord", remove.isolate = TRUE, scale=TRUE)
dev.off()
png 
  2 
# Chord diagram
#group.cellType <- c(rep("Fibro", 2), rep("B", 3), rep("SMG", 3)) # grouping cell clusters into fibroblast, DC and TC cells
#names(group.cellType) <- levels(cellchat@idents)
#netVisual_chord_cell(cellchat, signaling = pathways.show, group = group.cellType, title.name = paste0(pathways.show, " signaling network"))
netVisual_chord_cell(cellchat, signaling = pathways.show, title.name = paste0(pathways.show, " signaling network"))
Plot the aggregated cell-cell communication network at the signaling pathway level

netAnalysis_contribution(cellchat, signaling = "CXCL")

#to get a cursory look at which L-R pairs within a given network, can also look at the full overview on the cellchat database http://www.cellchat.org/cellchatdb/
netAnalysis_contribution(cellchat, signaling = "CCL")

#to get a cursory look at which L-R pairs within a given network, can also look at the full overview on the cellchat database http://www.cellchat.org/cellchatdb/
netAnalysis_contribution(cellchat, signaling = "MHC-II")

#to get a cursory look at which L-R pairs within a given network, can also look at the full overview on the cellchat database http://www.cellchat.org/cellchatdb/
netAnalysis_contribution(cellchat, signaling = "THBS")

#to get a cursory look at which L-R pairs within a given network, can also look at the full overview on the cellchat database http://www.cellchat.org/cellchatdb/
pathways.show = "CCL"
pairLR.CCL <- extractEnrichedLR(cellchat, signaling = pathways.show, geneLR.return = FALSE)
LR.show <- pairLR.CCL[6,]
pdf(file ="all_genes_plots/diseaseonly/cellchat_CCLnetvis_individual.pdf", width = 20, height =16)
netVisual_individual(cellchat, signaling = pathways.show, pairLR.use = LR.show, layout = "chord")
[[1]]
netVisual_aggregate(cellchat, signaling = 'CXCL', layout = "circle")

netVisual_aggregate(cellchat, signaling = 'SAA', layout = "circle")

netVisual_bubble(cellchat, sources.use = 57, remove.isolate = FALSE)
Comparing communications on a single object 

pdf(file ="all_genes_plots/diseaseonly/cellchat_MUC6source_netvisualbubble.pdf", width = 20, height =30)
netVisual_bubble(cellchat, sources.use = 57, remove.isolate = FALSE)
Comparing communications on a single object 
pdf(file ="all_genes_plots/diseaseonly/cellchat_MUC6target_netvisualbubble.pdf", width = 20, height =30)
netVisual_bubble(cellchat, targets.use = 57, remove.isolate = FALSE)
Comparing communications on a single object 
pdf(file ="all_genes_plots/diseaseonly/cellchat_OralFibrosource_netvisualbubble.pdf", width = 20, height =40)
netVisual_bubble(cellchat, sources.use = 63, remove.isolate = FALSE)
Comparing communications on a single object 

haven’t run any of this yet –>

netVisual_chord_gene <- function(object, slot.name = "net", color.use = NULL,
                                 signaling = NULL, pairLR.use = NULL, net = NULL,
                                 sources.use = NULL, targets.use = NULL,
                                 lab.cex = 0.8,small.gap = 1, big.gap = 10, annotationTrackHeight = c(0.03),
                                 link.visible = TRUE, scale = FALSE, directional = 1, link.target.prop = TRUE, reduce = -1,
                                 transparency = 0.4, link.border = NA,
                                 title.name = NULL, legend.pos.x = 20, legend.pos.y = 20, show.legend = TRUE,
                                 thresh = 0.05,
                                 ...){
  if (!is.null(pairLR.use)) {
    if (!is.data.frame(pairLR.use)) {
      stop("pairLR.use should be a data frame with a signle column named either 'interaction_name' or 'pathway_name' ")
    } else if ("pathway_name" %in% colnames(pairLR.use)) {
      message("slot.name is set to be 'netP' when pairLR.use contains signaling pathways")
      slot.name = "netP"
    }
  }

  if (!is.null(pairLR.use) & !is.null(signaling)) {
    stop("Please do not assign values to 'signaling' when using 'pairLR.use'")
  }

  if (is.null(net)) {
    prob <- slot(object, "net")$prob
    pval <- slot(object, "net")$pval
    prob[pval > thresh] <- 0
    net <- reshape2::melt(prob, value.name = "prob")
    colnames(net)[1:3] <- c("source","target","interaction_name")

    pairLR = dplyr::select(object@LR$LRsig, c("interaction_name_2", "pathway_name",  "ligand",  "receptor" ,"annotation","evidence"))
    idx <- match(net$interaction_name, rownames(pairLR))
    temp <- pairLR[idx,]
    net <- cbind(net, temp)
  }

  if (!is.null(signaling)) {
    pairLR.use <- data.frame()
    for (i in 1:length(signaling)) {
      pairLR.use.i <- searchPair(signaling = signaling[i], pairLR.use = object@LR$LRsig, key = "pathway_name", matching.exact = T, pair.only = T)
      pairLR.use <- rbind(pairLR.use, pairLR.use.i)
    }
  }

  if (!is.null(pairLR.use)){
    if ("interaction_name" %in% colnames(pairLR.use)) {
      net <- subset(net,interaction_name %in% pairLR.use$interaction_name)
    } else if ("pathway_name" %in% colnames(pairLR.use)) {
      net <- subset(net, pathway_name %in% as.character(pairLR.use$pathway_name))
    }
  }

  if (slot.name == "netP") {
    net <- dplyr::select(net, c("source","target","pathway_name","prob"))
    net$source_target <- paste(net$source, net$target, sep = "sourceTotarget")
    net <- net %>% dplyr::group_by(source_target, pathway_name) %>% dplyr::summarize(prob = sum(prob))
    a <- stringr::str_split(net$source_target, "sourceTotarget", simplify = T)
    net$source <- as.character(a[, 1])
    net$target <- as.character(a[, 2])
    net$ligand <- net$pathway_name
    net$receptor <- " "
  }

  # keep the interactions associated with sources and targets of interest
  if (!is.null(sources.use)){
    if (is.numeric(sources.use)) {
      sources.use <- levels(object@idents)[sources.use]
    }
    net <- subset(net, source %in% sources.use)
  } else {
    sources.use <- levels(object@idents)
  }
  if (!is.null(targets.use)){
    if (is.numeric(targets.use)) {
      targets.use <- levels(object@idents)[targets.use]
    }
    net <- subset(net, target %in% targets.use)
  } else {
    targets.use <- levels(object@idents)
  }
  # remove the interactions with zero values
  df <- subset(net, prob > 0)

  if (nrow(df) == 0) {
    stop("No signaling links are inferred! ")
  }

  if (length(unique(net$ligand)) == 1) {
    message("You may try the function `netVisual_chord_cell` for visualizing individual signaling pathway")
  }

  df$id <- 1:nrow(df)
  # deal with duplicated sector names
  ligand.uni <- unique(df$ligand)
  for (i in 1:length(ligand.uni)) {
    df.i <- df[df$ligand == ligand.uni[i], ]
    source.uni <- unique(df.i$source)
    for (j in 1:length(source.uni)) {
      df.i.j <- df.i[df.i$source == source.uni[j], ]
      df.i.j$ligand <- paste0(df.i.j$ligand, paste(rep(' ',j-1),collapse = ''))
      df$ligand[df$id %in% df.i.j$id] <- df.i.j$ligand
    }
  }
  receptor.uni <- unique(df$receptor)
  for (i in 1:length(receptor.uni)) {
    df.i <- df[df$receptor == receptor.uni[i], ]
    target.uni <- unique(df.i$target)
    for (j in 1:length(target.uni)) {
      df.i.j <- df.i[df.i$target == target.uni[j], ]
      df.i.j$receptor <- paste0(df.i.j$receptor, paste(rep(' ',j-1),collapse = ''))
      df$receptor[df$id %in% df.i.j$id] <- df.i.j$receptor
    }
  }

  cell.order.sources <- levels(object@idents)[levels(object@idents) %in% sources.use]
  cell.order.targets <- levels(object@idents)[levels(object@idents) %in% targets.use]

  df$source <- factor(df$source, levels = cell.order.sources)
  df$target <- factor(df$target, levels = cell.order.targets)
  # df.ordered.source <- df[with(df, order(source, target, -prob)), ]
  # df.ordered.target <- df[with(df, order(target, source, -prob)), ]
  df.ordered.source <- df[with(df, order(source, -prob)), ]
  df.ordered.target <- df[with(df, order(target, -prob)), ]

  order.source <- unique(df.ordered.source[ ,c('ligand','source')])
  order.target <- unique(df.ordered.target[ ,c('receptor','target')])

  # define sector order
  order.sector <- c(order.source$ligand, order.target$receptor)

  # define cell type color
  if (is.null(color.use)){
    color.use = scPalette(nlevels(object@idents))
    names(color.use) <- levels(object@idents)
    color.use <- color.use[levels(object@idents) %in% as.character(union(df$source,df$target))]
  } else if (is.null(names(color.use))) {
    names(color.use) <- levels(object@idents)
    color.use <- color.use[levels(object@idents) %in% as.character(union(df$source,df$target))]
  }

  # define edge color
  edge.color <- color.use[as.character(df.ordered.source$source)]
  names(edge.color) <- as.character(df.ordered.source$source)

  # define grid colors
  grid.col.ligand <- color.use[as.character(order.source$source)]
  names(grid.col.ligand) <- as.character(order.source$source)
  grid.col.receptor <- color.use[as.character(order.target$target)]
  names(grid.col.receptor) <- as.character(order.target$target)
  grid.col <- c(as.character(grid.col.ligand), as.character(grid.col.receptor))
  names(grid.col) <- order.sector

  df.plot <- df.ordered.source[ ,c('ligand','receptor','prob')]

  if (directional == 2) {
    link.arr.type = "triangle"
  } else {
    link.arr.type = "big.arrow"
  }
  circos.clear()
  chordDiagram(df.plot,
               order = order.sector,
               col = edge.color,
               grid.col = grid.col,
               transparency = transparency,
               link.border = link.border,
               directional = directional,
               direction.type = c("diffHeight","arrows"),
               link.arr.type = link.arr.type,
               annotationTrack = "grid",
               annotationTrackHeight = annotationTrackHeight,
               preAllocateTracks = list(track.height = max(strwidth(order.sector))),
               small.gap = small.gap,
               big.gap = big.gap,
               link.visible = link.visible,
               scale = scale,
               link.target.prop = link.target.prop,
               reduce = reduce,
               ...)

  circos.track(track.index = 1, panel.fun = function(x, y) {
    xlim = get.cell.meta.data("xlim")
    xplot = get.cell.meta.data("xplot")
    ylim = get.cell.meta.data("ylim")
    sector.name = get.cell.meta.data("sector.index")
    circos.text(mean(xlim), ylim[1], sector.name, facing = "bending", niceFacing = TRUE, adj=c(0.5,0.01),cex = lab.cex)
  }, bg.border = NA)


  # https://jokergoo.github.io/circlize_book/book/legends.html
  if (show.legend) {
    lgd <- ComplexHeatmap::Legend(at = names(color.use), type = "grid", legend_gp = grid::gpar(fill = color.use), title = "Cell State")
    ComplexHeatmap::draw(lgd, x = unit(1, "npc")-unit(legend.pos.x, "mm"), y = unit(legend.pos.y, "mm"), just = c("right", "bottom"))
  }

  circos.clear()
  if(!is.null(title.name)){
    text(-0, 1.02, title.name, cex=1)
  }
  gg <- recordPlot()
  return(gg)
}
netVisual_chord_gene(cellchat, signaling = c("SAA"),legend.pos.x = 8, scale=FALSE)#, sources.use = c(1,2,3,4,5,6,7), targets.use = c(1,2,3,4,5,6,7), lab.cex=1,  color.use = c('#CD6600', '#FF8C00', '#CD00CD','#0000EE', '#8FBC8F','#C1FFC1','#228B22')) 
colours = c('#db9602',#   'B_GC_I':
 '#e2d138',#   'B_GC_I':
'#a33c22',#   'B_memory':
  '#9b0319',# 'B_naive':
  '#f76c56',# 'B_plasma_IgA1':
  '#d6558d',# 'B_plasma_IgA2':
'#632f17',#   'B_plasma_IgG':
  '#c66d31',# 'B_plasma_IgM':
  '#9e53db',# 'B_plasmablast':
  '#8a4682',# 'B_preB':
'#d34794',#   'B_proB':
'#39997c',#   'BEST4_enterocyte_colonocyte':
'#bd7879',#   'Crypt_fibroblast_PI16':
'#8c543f',#   'DC_cDC1':
'#cfdb65',#   'DC_cDC2':
'#c7a642',#   'DC_langerhans':
'#e6a519',#   'DC_migratory':
'#bdb197',#   'DC_pDC':
'#fa6e6e',#   'EC_arterial_1':
'#ca6092',#   'EC_arterial_2':
'#855f9a',#   'EC_capillary':
'#fac06e',#   'EC_cycling':
'#999999',#   'EC_lymphatic':
'#2a4858',# 'EC_venous':
'#DBA507',#   'Enteric_neural_crest_cycling':
'#e1b5e6',#     'Enterocyte':
'#68b7fc',#   'Enteroendocrine':
  '#8b4eba',# 'Eosinophil/basophil':
  '#c924b9',# 'Epithelial_stem':
  '#0e539c',# 'Erythrocytes':
  '#f0c134',# 'Fibroblast_reticular':
'#f0982c',#   'Follicular_DC':
'#3fafb5',#   'gdT':
'#26daf2',#     'gdT_naive':
'#8EC7D2',#   'Glial_1':
'#0D6986',#   'Glial_2':
'#053240',#   'Glial_3':
'#a8c545',#   'Glial/Enteric_neural_crest':
'#6c9939',#     'Goblet':
'#d1d14f',# 'Goblet_cycling':
'#e9f7ad',# 'Goblet_progenitor':
'#778c00',#     'ILC3':
'#AAC789',#   'Immune_recruiting_pericyte':
'#e95e50',#   'Lamina_propria_fibroblast_ADAMDEC1':
'#486626',# 'Macrophage':
'#caf9cf',#   'Macrophage_CD5L':
'#8fd9d0',#   'Macrophage_LYVE1':
'#a5f002',#   'Macrophage_MMP9':
'#42c7ac',#   'Macrophage_TREM2':
'#21b796',#     'MAIT':
'#826e91',#   'Mast':
'#c730aa',#   'Megakaryocyte/platelet':
'#8F6592',#   'Mesothelium':
'#e55b85',#   'Microfold':
'#2a497a',#   'Mono/neutrophil_MPO':
'#5baf07',#   'Monocyte':
'#f7b37c',#   'Mucous_gland_neck':
'#CCAE91',#   'Myofibroblast':
'#c50637',#   'Neuroblast':
'#0c1e0e',#   'NK_CD16':
'#3f8c08',#   'NK_CD56bright':
'#63A0C0',#     'Oesophagus_fibroblast':
'#303267',#   'Oral_mucosa_fibroblast':
'#79508f',#   'Paneth':
'#437356',#     'Pericyte':
'#522e25',#   'Rectum_fibroblast':
'#d9b74a',#   'Surface_foveolar':
'#c260ff',#   'T/NK_cycling':
'#b85f1c',#   'TA':
'#5e0b30',# 'Tfh':
'#5e3c55',#   'Tfh_naive':
'#9c53bc',#     'Tnaive/cm_CD4':
'#5ca4ce',#   'Tnaive/cm_CD8':
'#f98261',#     'Treg':
'#e5c510',# 'Treg_IL10':
'#8107ed',#   'Trm_CD4':
'#2844c1',#   'Trm_CD8':
'#1e093f',#   'Trm_Th17':
'#256b87',#   'Trm/em_CD8':
'#9d9dff',#   'Tuft':
'#1E4147',#   'Vascular_smooth_muscle':
'#d64582'#   'Villus_fibroblast_F3':
)
netVisual_chord_gene(cellchat, signaling = c("SAA"), legend.pos.x = 8, scale=FALSE,sources.use = c(30,32,56,57,63), targets.use = c(30,32,56,57,63), lab.cex=1,color.use = colours) 
netVisual_chord_gene <- function(object, slot.name = "net", color.use = NULL,
                                 signaling = NULL, pairLR.use = NULL, net = NULL,
                                 sources.use = NULL, targets.use = NULL,
                                 lab.cex = 0.8,small.gap = 1, big.gap = 10, annotationTrackHeight = c(0.03),
                                 link.visible = TRUE, scale = FALSE, directional = 1, link.target.prop = TRUE, reduce = -1,
                                 transparency = 0.4, link.border = NA,
                                 title.name = NULL, legend.pos.x = 20, legend.pos.y = 20, show.legend = TRUE,
                                 thresh = 0.05,
                                 ...){
  if (!is.null(pairLR.use)) {
    if (!is.data.frame(pairLR.use)) {
      stop("pairLR.use should be a data frame with a signle column named either 'interaction_name' or 'pathway_name' ")
    } else if ("pathway_name" %in% colnames(pairLR.use)) {
      message("slot.name is set to be 'netP' when pairLR.use contains signaling pathways")
      slot.name = "netP"
    }
  }

  if (!is.null(pairLR.use) & !is.null(signaling)) {
    stop("Please do not assign values to 'signaling' when using 'pairLR.use'")
  }

  if (is.null(net)) {
    prob <- slot(object, "net")$prob
    pval <- slot(object, "net")$pval
    prob[pval > thresh] <- 0
    net <- reshape2::melt(prob, value.name = "prob")
    colnames(net)[1:3] <- c("source","target","interaction_name")

    pairLR = dplyr::select(object@LR$LRsig, c("interaction_name_2", "pathway_name",  "ligand",  "receptor" ,"annotation","evidence"))
    idx <- match(net$interaction_name, rownames(pairLR))
    temp <- pairLR[idx,]
    net <- cbind(net, temp)
  }

  if (!is.null(signaling)) {
    pairLR.use <- data.frame()
    for (i in 1:length(signaling)) {
      pairLR.use.i <- searchPair(signaling = signaling[i], pairLR.use = object@LR$LRsig, key = "pathway_name", matching.exact = T, pair.only = T)
      pairLR.use <- rbind(pairLR.use, pairLR.use.i)
    }
  }

  if (!is.null(pairLR.use)){
    if ("interaction_name" %in% colnames(pairLR.use)) {
      net <- subset(net,interaction_name %in% pairLR.use$interaction_name)
    } else if ("pathway_name" %in% colnames(pairLR.use)) {
      net <- subset(net, pathway_name %in% as.character(pairLR.use$pathway_name))
    }
  }

  if (slot.name == "netP") {
    net <- dplyr::select(net, c("source","target","pathway_name","prob"))
    net$source_target <- paste(net$source, net$target, sep = "sourceTotarget")
    net <- net %>% dplyr::group_by(source_target, pathway_name) %>% dplyr::summarize(prob = sum(prob))
    a <- stringr::str_split(net$source_target, "sourceTotarget", simplify = T)
    net$source <- as.character(a[, 1])
    net$target <- as.character(a[, 2])
    net$ligand <- net$pathway_name
    net$receptor <- " "
  }

  # keep the interactions associated with sources and targets of interest
  if (!is.null(sources.use)){
    if (is.numeric(sources.use)) {
      sources.use <- levels(object@idents)[sources.use]
    }
    net <- subset(net, source %in% sources.use)
  } else {
    sources.use <- levels(object@idents)
  }
  if (!is.null(targets.use)){
    if (is.numeric(targets.use)) {
      targets.use <- levels(object@idents)[targets.use]
    }
    net <- subset(net, target %in% targets.use)
  } else {
    targets.use <- levels(object@idents)
  }
  # remove the interactions with zero values
  df <- subset(net, prob > 0)

  if (nrow(df) == 0) {
    stop("No signaling links are inferred! ")
  }

  if (length(unique(net$ligand)) == 1) {
    message("You may try the function `netVisual_chord_cell` for visualizing individual signaling pathway")
  }

  df$id <- 1:nrow(df)
  # deal with duplicated sector names
  ligand.uni <- unique(df$ligand)
  for (i in 1:length(ligand.uni)) {
    df.i <- df[df$ligand == ligand.uni[i], ]
    source.uni <- unique(df.i$source)
    for (j in 1:length(source.uni)) {
      df.i.j <- df.i[df.i$source == source.uni[j], ]
      df.i.j$ligand <- paste0(df.i.j$ligand, paste(rep(' ',j-1),collapse = ''))
      df$ligand[df$id %in% df.i.j$id] <- df.i.j$ligand
    }
  }
  receptor.uni <- unique(df$receptor)
  for (i in 1:length(receptor.uni)) {
    df.i <- df[df$receptor == receptor.uni[i], ]
    target.uni <- unique(df.i$target)
    for (j in 1:length(target.uni)) {
      df.i.j <- df.i[df.i$target == target.uni[j], ]
      df.i.j$receptor <- paste0(df.i.j$receptor, paste(rep(' ',j-1),collapse = ''))
      df$receptor[df$id %in% df.i.j$id] <- df.i.j$receptor
    }
  }

  cell.order.sources <- levels(object@idents)[levels(object@idents) %in% sources.use]
  cell.order.targets <- levels(object@idents)[levels(object@idents) %in% targets.use]

  df$source <- factor(df$source, levels = cell.order.sources)
  df$target <- factor(df$target, levels = cell.order.targets)
  # df.ordered.source <- df[with(df, order(source, target, -prob)), ]
  # df.ordered.target <- df[with(df, order(target, source, -prob)), ]
  df.ordered.source <- df[with(df, order(source, -prob)), ]
  df.ordered.target <- df[with(df, order(target, -prob)), ]

  order.source <- unique(df.ordered.source[ ,c('ligand','source')])
  order.target <- unique(df.ordered.target[ ,c('receptor','target')])

  # define sector order
  order.sector <- c(order.source$ligand, order.target$receptor)

  # define cell type color
  if (is.null(color.use)){
    color.use = scPalette(nlevels(object@idents))
    names(color.use) <- levels(object@idents)
    color.use <- color.use[levels(object@idents) %in% as.character(union(df$source,df$target))]
  } else if (is.null(names(color.use))) {
    names(color.use) <- levels(object@idents)
    color.use <- color.use[levels(object@idents) %in% as.character(union(df$source,df$target))]
  }

  # define edge color
  edge.color <- color.use[as.character(df.ordered.source$source)]
  names(edge.color) <- as.character(df.ordered.source$source)

  # define grid colors
  grid.col.ligand <- color.use[as.character(order.source$source)]
  names(grid.col.ligand) <- as.character(order.source$source)
  grid.col.receptor <- color.use[as.character(order.target$target)]
  names(grid.col.receptor) <- as.character(order.target$target)
  grid.col <- c(as.character(grid.col.ligand), as.character(grid.col.receptor))
  names(grid.col) <- order.sector

  df.plot <- df.ordered.source[ ,c('ligand','receptor','prob')]

  if (directional == 2) {
    link.arr.type = "triangle"
  } else {
    link.arr.type = "big.arrow"
  }
  circos.clear()
  chordDiagram(df.plot,
               order = order.sector,
               col = edge.color,
               grid.col = grid.col,
               transparency = transparency,
               link.border = link.border,
               directional = directional,
               direction.type = c("diffHeight","arrows"),
               link.arr.type = link.arr.type,
               annotationTrack = "grid",
               annotationTrackHeight = annotationTrackHeight,
               preAllocateTracks = list(track.height = max(strwidth(order.sector))),
               small.gap = small.gap,
               big.gap = big.gap,
               link.visible = link.visible,
               scale = scale,
               link.target.prop = link.target.prop,
               reduce = reduce,
               ...)

  circos.track(track.index = 1, panel.fun = function(x, y) {
    xlim = get.cell.meta.data("xlim")
    xplot = get.cell.meta.data("xplot")
    ylim = get.cell.meta.data("ylim")
    sector.name = get.cell.meta.data("sector.index")
    circos.text(mean(xlim), ylim[1], sector.name,facing = "clockwise", niceFacing = TRUE, adj=c(0.5,0.01),cex = lab.cex)
  }, bg.border = NA)


  # https://jokergoo.github.io/circlize_book/book/legends.html
  if (show.legend) {
    lgd <- ComplexHeatmap::Legend(at = names(color.use), type = "grid", legend_gp = grid::gpar(fill = color.use), title = "Cell State")
    ComplexHeatmap::draw(lgd, x = unit(1, "npc")-unit(legend.pos.x, "mm"), y = unit(legend.pos.y, "mm"), just = c("right", "bottom"))
  }

  circos.clear()
  if(!is.null(title.name)){
    text(-0, 1.02, title.name, cex=1)
  }
  gg <- recordPlot()
  return(gg)
}
netVisual_chord_gene(cellchat, signaling = c("CXCL"), legend.pos.x = 8, scale=FALSE,sources.use = c(57,63), lab.cex=0.5,color.use = colours) 
netVisual_chord_gene(cellchat, signaling = c("CXCL"), legend.pos.x = 8, scale=TRUE,sources.use = c(57,63),targets.use =c(24,29,46,50,60,62,69,70,72,73), lab.cex=0.5,color.use = colours) 
pdf(file ="all_genes_plots/cellchat_MUC6OralFibrosource_cxclchord.pdf", width = 15, height =15)
netVisual_chord_gene(cellchat, signaling = c("CXCL"), legend.pos.x = 8, scale=TRUE,sources.use = c(57,63),targets.use =c(24,29,46,50,60,62,69,70,72,73), lab.cex=0.5,color.use = colours) 
netVisual_chord_gene(cellchat, signaling = c("CXCL"), legend.pos.x = 8, scale=TRUE,sources.use = c(57), lab.cex=1,color.use = colours) 
pdf(file ="all_genes_plots/cellchat_MUC6source_cxclchord.pdf", width = 15, height =15)
netVisual_chord_gene(cellchat, signaling = c("CXCL"), legend.pos.x = 8, scale=TRUE,sources.use = c(57), lab.cex=1,color.use = colours) 
netVisual_chord_gene(cellchat, signaling = c("CCL"), legend.pos.x = 8, scale=FALSE,sources.use = c(57,63), lab.cex=0.5,color.use = colours) 
netVisual_chord_gene(cellchat, signaling = c("CXCL"), legend.pos.x = 8, scale=FALSE,sources.use = c(57,63), lab.cex=0.5,color.use = colours) 
netVisual_chord_gene(cellchat, signaling = c("MHC-II"), legend.pos.x = 8, scale=FALSE,sources.use = c(57), lab.cex=0.5,color.use = colours) 

code from previous notebook

netVisual_chord_gene(cellchat, signaling = c("IL6"),legend.pos.x = 8, scale=FALSE, sources.use = c(1,2,3,4,5,6,7), targets.use = c(1,2,3,4,5,6,7), lab.cex=1,  color.use = c('#CD6600', '#FF8C00', '#CD00CD','#0000EE', '#8FBC8F','#C1FFC1','#228B22')) 
netVisual_chord_gene(cellchat, signaling = c("CCL"),legend.pos.x = 8, scale=TRUE, sources.use = c(5,6,7), targets.use = c(1,2,3,4,5,6,7), lab.cex=0.5,  color.use = c('#CD6600', '#FF8C00', '#CD00CD', '#0000EE',  '#8FBC8F','#C1FFC1','#228B22')) 
netVisual_chord_gene(cellchat, signaling = c("IL6"),legend.pos.x = 8, scale=TRUE, sources.use = c(5,6,7), targets.use = c(1,2,3,4), lab.cex=1.5, color.use = c('#CD6600', '#FF8C00', '#CD00CD',  '#4169E1', '#0000EE', '#ADD8E6', '#8FBC8F','#C1FFC1','#228B22','#6495ED')) 
netVisual_chord_gene(cellchat, signaling = c("IL6"),legend.pos.x = 8, scale=TRUE, lab.cex=1,  color.use = c('#CD6600', '#FF8C00', '#CD00CD','#0000EE', '#8FBC8F','#C1FFC1','#228B22'))

Below is just changes to the default circle/chord plots from the source code, the default option is to have the labels sticking out from the plot instead of wrapping around this can be changed in circos.text setting facing (https://www.rdocumentation.org/packages/circlize/versions/0.4.13/topics/circos.text)

#HLA-DRA
pathways.show <- c("MHC-II")
pairLR.MHCII <- extractEnrichedLR(cellchat, signaling = pathways.show, geneLR.return = FALSE)
LR.show <- pairLR.MHCII[11,] #HLA-DRA is 10 and HLA-DRB1 is 11
netVisual_individual(cellchat, signaling = pathways.show, pairLR.use = LR.show, layout = "chord", color.use = c('#CD6600', '#FF8C00', '#CD00CD',  '#4169E1', '#0000EE', '#ADD8E6', '#8FBC8F','#C1FFC1','#228B22','#6495ED'),remove.isolate=TRUE)
netVisual_individual <- function(object, signaling, signaling.name = NULL, pairLR.use = NULL, color.use = NULL, vertex.receiver = NULL, sources.use = NULL, targets.use = NULL, top = 1, remove.isolate = FALSE,
                                 vertex.weight = 1, vertex.weight.max = NULL, vertex.size.max = NULL, vertex.label.cex = 0.8,
                                 weight.scale = FALSE, edge.weight.max = NULL, edge.width.max=8, graphics.init = TRUE,
                                 layout = c("circle","hierarchy","chord"), height = 5, thresh = 0.05, #from = NULL, to = NULL, bidirection = NULL,vertex.size = NULL,
                                 group = NULL,cell.order = NULL,small.gap = 1, big.gap = 10, scale = FALSE, reduce = -1, show.legend = FALSE, legend.pos.x = 20, legend.pos.y = 20, nCol = NULL,
                                 ...) {
  layout <- match.arg(layout)
  # if (!is.null(vertex.size)) {
  #   warning("'vertex.size' is deprecated. Use `vertex.weight`")
  # }
  if (is.null(vertex.weight)) {
    vertex.weight <- as.numeric(table(object@idents))
  }
  if (is.null(vertex.size.max)) {
    if (length(unique(vertex.weight)) == 1) {
      vertex.size.max <- 5
    } else {
      vertex.size.max <- 15
    }
  }

  pairLR <- searchPair(signaling = signaling, pairLR.use = object@LR$LRsig, key = "pathway_name", matching.exact = T, pair.only = F)

  if (is.null(signaling.name)) {
    signaling.name <- signaling
  }
  net <- object@net

  pairLR.use.name <- dimnames(net$prob)[[3]]
  pairLR.name <- intersect(rownames(pairLR), pairLR.use.name)
  if (!is.null(pairLR.use)) {
    if (is.data.frame(pairLR.use)) {
      pairLR.name <- intersect(pairLR.name, as.character(pairLR.use$interaction_name))
    } else {
      pairLR.name <- intersect(pairLR.name, as.character(pairLR.use))
    }

    if (length(pairLR.name) == 0) {
      stop("There is no significant communication for the input L-R pairs!")
    }
  }

  pairLR <- pairLR[pairLR.name, ]
  prob <- net$prob
  pval <- net$pval

  prob[pval > thresh] <- 0
  if (length(pairLR.name) > 1) {
    pairLR.name.use <- pairLR.name[apply(prob[,,pairLR.name], 3, sum) != 0]
  } else {
    pairLR.name.use <- pairLR.name[sum(prob[,,pairLR.name]) != 0]
  }

  if (length(pairLR.name.use) == 0) {
    stop(paste0('There is no significant communication of ', signaling.name))
  } else {
    pairLR <- pairLR[pairLR.name.use,]
  }

  nRow <- length(pairLR.name.use)

  prob <- prob[,,pairLR.name.use]
  pval <- pval[,,pairLR.name.use]

  if (is.null(nCol)) {
    nCol <- min(length(pairLR.name.use), 2)
  }

  if (length(dim(prob)) == 2) {
    prob <- replicate(1, prob, simplify="array")
    pval <- replicate(1, pval, simplify="array")
  }

 # prob <-(prob-min(prob))/(max(prob)-min(prob))
  if (is.null(edge.weight.max)) {
    edge.weight.max = max(prob)
  }

  if (layout == "hierarchy") {
    if (graphics.init) {
      par(mfrow=c(nRow,2), mar = c(5, 4, 4, 2) +0.1)
    }

    for (i in 1:length(pairLR.name.use)) {
      signalName_i <- pairLR$interaction_name_2[i]
      prob.i <- prob[,,i]
      netVisual_hierarchy1(prob.i, vertex.receiver = vertex.receiver, sources.use = sources.use, targets.use = targets.use, remove.isolate = remove.isolate, top = top, color.use = color.use, vertex.weight = vertex.weight, vertex.weight.max = vertex.weight.max, vertex.size.max = vertex.size.max, weight.scale = weight.scale, edge.weight.max = edge.weight.max, edge.width.max=edge.width.max, title.name = signalName_i,...)
      netVisual_hierarchy2(prob.i, vertex.receiver = setdiff(1:nrow(prob.i),vertex.receiver), sources.use = sources.use, targets.use = targets.use, remove.isolate = remove.isolate, top = top, color.use = color.use, vertex.weight = vertex.weight, vertex.weight.max = vertex.weight.max, vertex.size.max = vertex.size.max, weight.scale = weight.scale, edge.weight.max = edge.weight.max, edge.width.max=edge.width.max, title.name = signalName_i,...)
    }
    # grid.echo()
    # gg <-  grid.grab()
    gg <- recordPlot()

  } else if (layout == "circle") {
   # par(mfrow=c(nRow,1))
    if (graphics.init) {
      par(mfrow = c(ceiling(length(pairLR.name.use)/nCol), nCol), xpd=TRUE)
    }

    gg <- vector("list", length(pairLR.name.use))
    for (i in 1:length(pairLR.name.use)) {
      signalName_i <- pairLR$interaction_name_2[i]
      prob.i <- prob[,,i]
      gg[[i]] <- netVisual_circle(prob.i, sources.use = sources.use, targets.use = targets.use, remove.isolate = remove.isolate, top = top, color.use = color.use, vertex.weight = vertex.weight, vertex.weight.max = vertex.weight.max, vertex.size.max = vertex.size.max, weight.scale = weight.scale, edge.weight.max = edge.weight.max, edge.width.max=edge.width.max, title.name = signalName_i,...)
    }
  } else if (layout == "chord") {
    if (graphics.init) {
      par(mfrow = c(ceiling(length(pairLR.name.use)/nCol), nCol), xpd=TRUE)
    }

    gg <- vector("list", length(pairLR.name.use))
    for (i in 1:length(pairLR.name.use)) {
      title.name <- pairLR$interaction_name_2[i]
      net <- prob[,,i]
      gg[[i]] <- netVisual_chord_cell_internal(net, color.use = color.use, sources.use = sources.use, targets.use = targets.use, remove.isolate = remove.isolate,
                                               group = group, cell.order = cell.order,
                                               lab.cex = vertex.label.cex,small.gap = small.gap, big.gap = big.gap,
                                               scale = scale, reduce = reduce,
                                               title.name = title.name, show.legend = show.legend, legend.pos.x = legend.pos.x, legend.pos.y = legend.pos.y)
    }
  }
  return(gg)
}
netVisual_chord_cell_internal <- function(net, color.use = NULL, group = NULL, cell.order = NULL,
                                          sources.use = NULL, targets.use = NULL,
                                          lab.cex = 0.8,small.gap = 1, big.gap = 10, annotationTrackHeight = c(0.03),
                                          remove.isolate = FALSE, link.visible = TRUE, scale = FALSE, directional = 1, link.target.prop = TRUE, reduce = -1,
                                          transparency = 0.4, link.border = NA,
                                          title.name = NULL, show.legend = FALSE, legend.pos.x = 20, legend.pos.y = 20,...){
  if (inherits(x = net, what = c("matrix", "Matrix"))) {
    cell.levels <- union(rownames(net), colnames(net))
    net <- reshape2::melt(net, value.name = "prob")
    colnames(net)[1:2] <- c("source","target")
  } else if (is.data.frame(net)) {
    if (all(c("source","target", "prob") %in% colnames(net)) == FALSE) {
      stop("The input data frame must contain three columns named as source, target, prob")
    }
    cell.levels <- as.character(union(net$source,net$target))
  }
  if (!is.null(cell.order)) {
    cell.levels <- cell.order
  }
  net$source <- as.character(net$source)
  net$target <- as.character(net$target)

  # keep the interactions associated with sources and targets of interest
  if (!is.null(sources.use)){
    if (is.numeric(sources.use)) {
      sources.use <- cell.levels[sources.use]
    }
    net <- subset(net, source %in% sources.use)
  }
  if (!is.null(targets.use)){
    if (is.numeric(targets.use)) {
      targets.use <- cell.levels[targets.use]
    }
    net <- subset(net, target %in% targets.use)
  }
  # remove the interactions with zero values
  net <- subset(net, prob > 0)
  # create a fake data if keeping the cell types (i.e., sectors) without any interactions
  if (!remove.isolate) {
    cells.removed <- setdiff(cell.levels, as.character(union(net$source,net$target)))
    if (length(cells.removed) > 0) {
      net.fake <- data.frame(cells.removed, cells.removed, 1e-10*sample(length(cells.removed), length(cells.removed)))
      colnames(net.fake) <- colnames(net)
      net <- rbind(net, net.fake)
      link.visible <- net[, 1:2]
      link.visible$plot <- FALSE
      link.visible$plot[1:(nrow(net) - nrow(net.fake))] <- TRUE
      # directional <- net[, 1:2]
      # directional$plot <- 0
      # directional$plot[1:(nrow(net) - nrow(net.fake))] <- 1
      # link.arr.type = "big.arrow"
      # message("Set scale = TRUE when remove.isolate = FALSE")
      scale = TRUE
    }
  }

  df <- net
  cells.use <- union(df$source,df$target)

  # define grid order
  order.sector <- cell.levels[cell.levels %in% cells.use]

  # define grid color
  if (is.null(color.use)){
    color.use = scPalette(length(cell.levels))
    names(color.use) <- cell.levels
  } else if (is.null(names(color.use))) {
    names(color.use) <- cell.levels
  }
  grid.col <- color.use[order.sector]
  names(grid.col) <- order.sector

  # set grouping information
  if (!is.null(group)) {
    group <- group[names(group) %in% order.sector]
  }

  # define edge color
  edge.color <- color.use[as.character(df$source)]

  if (directional == 0 | directional == 2) {
    link.arr.type = "triangle"
  } else {
    link.arr.type = "big.arrow"
  }

  circos.clear()
  chordDiagram(df,
               order = order.sector,
               col = edge.color,
               grid.col = grid.col,
               transparency = transparency,
               link.border = link.border,
               directional = directional,
               direction.type = c("diffHeight","arrows"),
               link.arr.type = link.arr.type, # link.border = "white",
               annotationTrack = "grid",
               annotationTrackHeight = annotationTrackHeight,
               preAllocateTracks = list(track.height = max(strwidth(order.sector))),
               small.gap = small.gap,
               big.gap = big.gap,
               link.visible = link.visible,
               scale = scale,
               group = group,
               link.target.prop = link.target.prop,
               reduce = reduce,
               ...)
  circos.track(track.index = 1, panel.fun = function(x, y) {
    xlim = get.cell.meta.data("xlim")
    xplot = get.cell.meta.data("xplot")
    ylim = get.cell.meta.data("ylim")
    sector.name = get.cell.meta.data("sector.index")
    circos.text(mean(xlim), ylim[1], sector.name, facing = "bending", niceFacing = TRUE, adj = c(0, 0.5),cex = lab.cex)
  }, bg.border = NA)

  # https://jokergoo.github.io/circlize_book/book/legends.html
  if (show.legend) {
    lgd <- ComplexHeatmap::Legend(at = names(grid.col), type = "grid", legend_gp = grid::gpar(fill = grid.col), title = "Cell State")
    ComplexHeatmap::draw(lgd, x = unit(1, "npc")-unit(legend.pos.x, "mm"), y = unit(legend.pos.y, "mm"), just = c("right", "bottom"))
  }

  if(!is.null(title.name)){
    # title(title.name, cex = 1)
    text(-0, 1.02, title.name, cex=1)
  }
  circos.clear()
  gg <- recordPlot()
  return(gg)
}
netVisual_chord_gene <- function(object, slot.name = "net", color.use = NULL,
                                 signaling = NULL, pairLR.use = NULL, net = NULL,
                                 sources.use = NULL, targets.use = NULL,
                                 lab.cex = 0.8,small.gap = 1, big.gap = 10, annotationTrackHeight = c(0.03),
                                 link.visible = TRUE, scale = FALSE, directional = 1, link.target.prop = TRUE, reduce = -1,
                                 transparency = 0.4, link.border = NA,
                                 title.name = NULL, legend.pos.x = 20, legend.pos.y = 20, show.legend = TRUE,
                                 thresh = 0.05,
                                 ...){
  if (!is.null(pairLR.use)) {
    if (!is.data.frame(pairLR.use)) {
      stop("pairLR.use should be a data frame with a signle column named either 'interaction_name' or 'pathway_name' ")
    } else if ("pathway_name" %in% colnames(pairLR.use)) {
      message("slot.name is set to be 'netP' when pairLR.use contains signaling pathways")
      slot.name = "netP"
    }
  }

  if (!is.null(pairLR.use) & !is.null(signaling)) {
    stop("Please do not assign values to 'signaling' when using 'pairLR.use'")
  }

  if (is.null(net)) {
    prob <- slot(object, "net")$prob
    pval <- slot(object, "net")$pval
    prob[pval > thresh] <- 0
    net <- reshape2::melt(prob, value.name = "prob")
    colnames(net)[1:3] <- c("source","target","interaction_name")

    pairLR = dplyr::select(object@LR$LRsig, c("interaction_name_2", "pathway_name",  "ligand",  "receptor" ,"annotation","evidence"))
    idx <- match(net$interaction_name, rownames(pairLR))
    temp <- pairLR[idx,]
    net <- cbind(net, temp)
  }

  if (!is.null(signaling)) {
    pairLR.use <- data.frame()
    for (i in 1:length(signaling)) {
      pairLR.use.i <- searchPair(signaling = signaling[i], pairLR.use = object@LR$LRsig, key = "pathway_name", matching.exact = T, pair.only = T)
      pairLR.use <- rbind(pairLR.use, pairLR.use.i)
    }
  }

  if (!is.null(pairLR.use)){
    if ("interaction_name" %in% colnames(pairLR.use)) {
      net <- subset(net,interaction_name %in% pairLR.use$interaction_name)
    } else if ("pathway_name" %in% colnames(pairLR.use)) {
      net <- subset(net, pathway_name %in% as.character(pairLR.use$pathway_name))
    }
  }

  if (slot.name == "netP") {
    net <- dplyr::select(net, c("source","target","pathway_name","prob"))
    net$source_target <- paste(net$source, net$target, sep = "sourceTotarget")
    net <- net %>% dplyr::group_by(source_target, pathway_name) %>% dplyr::summarize(prob = sum(prob))
    a <- stringr::str_split(net$source_target, "sourceTotarget", simplify = T)
    net$source <- as.character(a[, 1])
    net$target <- as.character(a[, 2])
    net$ligand <- net$pathway_name
    net$receptor <- " "
  }

  # keep the interactions associated with sources and targets of interest
  if (!is.null(sources.use)){
    if (is.numeric(sources.use)) {
      sources.use <- levels(object@idents)[sources.use]
    }
    net <- subset(net, source %in% sources.use)
  } else {
    sources.use <- levels(object@idents)
  }
  if (!is.null(targets.use)){
    if (is.numeric(targets.use)) {
      targets.use <- levels(object@idents)[targets.use]
    }
    net <- subset(net, target %in% targets.use)
  } else {
    targets.use <- levels(object@idents)
  }
  # remove the interactions with zero values
  df <- subset(net, prob > 0)

  if (nrow(df) == 0) {
    stop("No signaling links are inferred! ")
  }

  if (length(unique(net$ligand)) == 1) {
    message("You may try the function `netVisual_chord_cell` for visualizing individual signaling pathway")
  }

  df$id <- 1:nrow(df)
  # deal with duplicated sector names
  ligand.uni <- unique(df$ligand)
  for (i in 1:length(ligand.uni)) {
    df.i <- df[df$ligand == ligand.uni[i], ]
    source.uni <- unique(df.i$source)
    for (j in 1:length(source.uni)) {
      df.i.j <- df.i[df.i$source == source.uni[j], ]
      df.i.j$ligand <- paste0(df.i.j$ligand, paste(rep(' ',j-1),collapse = ''))
      df$ligand[df$id %in% df.i.j$id] <- df.i.j$ligand
    }
  }
  receptor.uni <- unique(df$receptor)
  for (i in 1:length(receptor.uni)) {
    df.i <- df[df$receptor == receptor.uni[i], ]
    target.uni <- unique(df.i$target)
    for (j in 1:length(target.uni)) {
      df.i.j <- df.i[df.i$target == target.uni[j], ]
      df.i.j$receptor <- paste0(df.i.j$receptor, paste(rep(' ',j-1),collapse = ''))
      df$receptor[df$id %in% df.i.j$id] <- df.i.j$receptor
    }
  }

  cell.order.sources <- levels(object@idents)[levels(object@idents) %in% sources.use]
  cell.order.targets <- levels(object@idents)[levels(object@idents) %in% targets.use]

  df$source <- factor(df$source, levels = cell.order.sources)
  df$target <- factor(df$target, levels = cell.order.targets)
  # df.ordered.source <- df[with(df, order(source, target, -prob)), ]
  # df.ordered.target <- df[with(df, order(target, source, -prob)), ]
  df.ordered.source <- df[with(df, order(source, -prob)), ]
  df.ordered.target <- df[with(df, order(target, -prob)), ]

  order.source <- unique(df.ordered.source[ ,c('ligand','source')])
  order.target <- unique(df.ordered.target[ ,c('receptor','target')])

  # define sector order
  order.sector <- c(order.source$ligand, order.target$receptor)

  # define cell type color
  if (is.null(color.use)){
    color.use = scPalette(nlevels(object@idents))
    names(color.use) <- levels(object@idents)
    color.use <- color.use[levels(object@idents) %in% as.character(union(df$source,df$target))]
  } else if (is.null(names(color.use))) {
    names(color.use) <- levels(object@idents)
    color.use <- color.use[levels(object@idents) %in% as.character(union(df$source,df$target))]
  }

  # define edge color
  edge.color <- color.use[as.character(df.ordered.source$source)]
  names(edge.color) <- as.character(df.ordered.source$source)

  # define grid colors
  grid.col.ligand <- color.use[as.character(order.source$source)]
  names(grid.col.ligand) <- as.character(order.source$source)
  grid.col.receptor <- color.use[as.character(order.target$target)]
  names(grid.col.receptor) <- as.character(order.target$target)
  grid.col <- c(as.character(grid.col.ligand), as.character(grid.col.receptor))
  names(grid.col) <- order.sector

  df.plot <- df.ordered.source[ ,c('ligand','receptor','prob')]

  if (directional == 2) {
    link.arr.type = "triangle"
  } else {
    link.arr.type = "big.arrow"
  }
  circos.clear()
  chordDiagram(df.plot,
               order = order.sector,
               col = edge.color,
               grid.col = grid.col,
               transparency = transparency,
               link.border = link.border,
               directional = directional,
               direction.type = c("diffHeight","arrows"),
               link.arr.type = link.arr.type,
               annotationTrack = "grid",
               annotationTrackHeight = annotationTrackHeight,
               preAllocateTracks = list(track.height = max(strwidth(order.sector))),
               small.gap = small.gap,
               big.gap = big.gap,
               link.visible = link.visible,
               scale = scale,
               link.target.prop = link.target.prop,
               reduce = reduce,
               ...)

  circos.track(track.index = 1, panel.fun = function(x, y) {
    xlim = get.cell.meta.data("xlim")
    xplot = get.cell.meta.data("xplot")
    ylim = get.cell.meta.data("ylim")
    sector.name = get.cell.meta.data("sector.index")
    circos.text(mean(xlim), ylim[1], sector.name, facing = "bending", niceFacing = TRUE, adj=c(0.5,0.01),cex = lab.cex)
  }, bg.border = NA)


  # https://jokergoo.github.io/circlize_book/book/legends.html
  if (show.legend) {
    lgd <- ComplexHeatmap::Legend(at = names(color.use), type = "grid", legend_gp = grid::gpar(fill = color.use), title = "Cell State")
    ComplexHeatmap::draw(lgd, x = unit(1, "npc")-unit(legend.pos.x, "mm"), y = unit(legend.pos.y, "mm"), just = c("right", "bottom"))
  }

  circos.clear()
  if(!is.null(title.name)){
    text(-0, 1.02, title.name, cex=1)
  }
  gg <- recordPlot()
  return(gg)
}
netVisual_chord_gene(cellchat, signaling = c("CCL"), 
                     #sources.use = c(1,2,3,5,6,7,8), targets.use = c(1,2,3,5,6,7,8), 
legend.pos.x = 8,scale=TRUE, color.use = c('#CD6600', '#FF8C00', '#CD00CD', #'#388E8E', 
'#80007c', '#8FBC8F', '#C1FFC1', '#228B22'),lab.cex = 0.8) 
a <- netVisual_chord_gene(cellchat, signaling = c("CCL"), 
                     #sources.use = c(1,2,3,5,6,7,8), targets.use = c(1,2,3,5,6,7,8), 
legend.pos.x = 8,scale=TRUE, color.use = c('#CD6600', '#FF8C00', '#CD00CD', #'#388E8E', 
'#BF8FAF', '#8FBC8F', '#C1FFC1', '#228B22'),lab.cex = 1) 
jpeg("final_figures/CXCL_chord.jpeg",width=30,height=30,units="cm",quality=100,res=300)
netVisual_chord_gene(cellchat, signaling = c("CXCL"), 
                     #sources.use = c(1,2,3,5,6,7,8), targets.use = c(1,2,3,5,6,7,8), 
legend.pos.x = 8,scale=TRUE, color.use = c('#CD6600', '#FF8C00', '#CD00CD', #'#388E8E', 
'#BC8F8F', '#8FBC8F', '#C1FFC1', '#228B22'),lab.cex = 3) 
dev.off()
LS0tCnRpdGxlOiAiQ2VsbGNoYXQgc2NyaXB0IgpkYXRlOiAiMTUvMDUvMjMiCmF1dGhvcjogIkFtYW5kYSBPbGl2ZXIiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClByZXByb2Nlc3NpbmcgaW4gcHl0aG9uOiBicmllZmx5IEkgbm9ybWFsaXNlZCBhbmQgbG9nIHRyYW5zZm9ybWVkIHRoZSByYXcgY291bnRzIGRhdGEsIGZpbHRlcmVkIGZvciBjZWxsdHlwZXMvY29uZGl0aW9ucyBvZiBpbnRlcmVzdCBhbmQgZXhwb3J0IHRoZSBub3JtYWxpc2VkIGNvdW50cyBhcyBjc3YgKHNhbWUgYXMgY2VsbHBob25lREIpLCBhbHNvIGV4cG9ydCBtZXRhZGF0YSBmb3IgY2VsbCB0eXBlIChsZXZlbF8zX2Fubm90KS4KCkluc3RhbGwgQ2VsbENoYXQgKGh0dHBzOi8vZ2l0aHViLmNvbS9zcWppbi9DZWxsQ2hhdCkKYGBge3J9CiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImpva2VyZ29vL0NvbXBsZXhIZWF0bWFwIikKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigiam9rZXJnb28vY2lyY2xpemUiKQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJzcWppbi9DZWxsQ2hhdCIpCmBgYAoKSW5zdGFsbCBvdGhlciBkZXBlbmRlbmNpZXMKYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzKCdOTUYnKQpgYGAKCkxvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KENlbGxDaGF0KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KHBseXIpCm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKbGlicmFyeShOTUYpCmxpYnJhcnkoZHBseXIpCiNsaWJyYXJ5KHNjZWFzeSkKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dhbGx1dmlhbCkKbGlicmFyeShjaXJjbGl6ZSkKYGBgCgpMb2FkIGlucHV0IGRhdGEgYW5kIG1ldGEgZGF0YQpgYGB7cn0KZGF0YSA8LSByZWFkLnRhYmxlKGZpbGUgPSAnL25mcy90ZWFtMjA1L2FvMTUvTWVnYWd1dC9Bbm5vdGF0aW9uc192My9kaXNlYXNlX2FuYWx5c2lzL2ludGVyYWN0aW9ucy9jb3VudHMvcG9vbGVkX2Rpc2Vhc2UucmVtYXBwZWQuYWxsZ2VuZXMuQVBfU0kuY291bnRzLmNzdicsIGhlYWRlciA9IFQsIHJvdy5uYW1lcz0xLCBzZXA9IiwiLCBhcy5pcz1UKQpoZWFkKGRhdGFbLDE6MTBdKQptZXRhIDwtIHJlYWQuY3N2KGZpbGUgPSAnL25mcy90ZWFtMjA1L2FvMTUvTWVnYWd1dC9Bbm5vdGF0aW9uc192My9kaXNlYXNlX2FuYWx5c2lzL2ludGVyYWN0aW9ucy9tZXRhL3Bvb2xlZF9kaXNlYXNlLnJlbWFwcGVkLmFsbGdlbmVzLkFQX1NJLm1ldGEuY3N2JywgaGVhZGVyID0gVCwgcm93Lm5hbWVzPTEsc2VwPSIsIiwgYXMuaXM9VCkKCmBgYAoKYGBge3J9CmhlYWQoZGF0YVssMToxMF0pCmBgYAoKYGBge3J9CmhlYWQobWV0YSkKYGBgCgoKYGBge3J9CiN0byBtYWtlIHRoZSBiYXJjb2RlcyBpbiBjb3VudHMgY29uc2lzdGVudCwgZm9yIHNvbWUgcmVhc29uIHRoZSBiYXJjb2RlcyB0aGF0IHJlYWQgIkFBQ0NHQ0dDQUdUVFRBQ0ctSENBX0FfR1QxMjkzNDk5OCIgYXJlIGJlaW5nIGNoYW5nZWQgdG8gIkFBQ0NHQ0dDQUdUVFRBQ0cuSENBX0FfR1QxMjkzNDk5OCIKY29sbmFtZXMoZGF0YSkgPSBnc3ViKCdbLl0nLCAnLScsIGNvbG5hbWVzKGRhdGEpKQojaGVhZChkYXRhWywxOjEwXSkKCiNxdWlja2x5IGxpc3QgYmFyY29kZXMgYnkgdHJhbnNwb3NpbmcgZGF0YWZyYW1lCiNkYXRhX3QgPC0gdChkYXRhKQojcm93Lm5hbWVzKGRhdGFfdCkKaGVhZChkYXRhWywxOjEwXSkKYGBgCgpNYWtlIHNldXJhdCBvYmplY3QgZnJvbSBjc3YKYGBge3J9CnNyYXQgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGRhdGEsIHByb2plY3QgPSAiTVVDNiIsIGFzc2F5ID0gIlJOQSIsIG1pbi5jZWxscyA9IDAsIG1pbi5mZWF0dXJlcyA9IDAsIG1ldGEuZGF0YSA9IG1ldGEpCmBgYAoKRnJvbSBoZXJlIHRoZSBzY3JpcHQgZm9sbG93cyB0aGUgQ2VsbENoYXQgdHV0b3JpYWwKYGBge3J9CmRhdGEuaW5wdXQgPC0gc3JhdEBhc3NheXMkUk5BQGNvdW50cwoKY2VsbC51c2UgPSByb3duYW1lcyhtZXRhKQpgYGAKCgpDcmVhdGUgYSBjZWxsY2hhdCBvYmplY3Q6CmBgYHtyfQpjZWxsY2hhdCA8LSBjcmVhdGVDZWxsQ2hhdChvYmplY3QgPSBkYXRhLmlucHV0LCBtZXRhID0gbWV0YSwgZ3JvdXAuYnkgPSAibGV2ZWxfM19hbm5vdCIpCmBgYAoKYGBge3J9CmNlbGxjaGF0IDwtIGFkZE1ldGEoY2VsbGNoYXQsIG1ldGEgPSBtZXRhKQpjZWxsY2hhdCA8LSBzZXRJZGVudChjZWxsY2hhdCwgaWRlbnQudXNlID0gImxldmVsXzNfYW5ub3QiKSAjIHNldCAibGFiZWxzIiBhcyBkZWZhdWx0IGNlbGwgaWRlbnRpdHkKbGV2ZWxzKGNlbGxjaGF0QGlkZW50cykgIyBzaG93IGZhY3RvciBsZXZlbHMgb2YgdGhlIGNlbGwgbGFiZWxzCmdyb3VwU2l6ZSA8LSBhcy5udW1lcmljKHRhYmxlKGNlbGxjaGF0QGlkZW50cykpICMgbnVtYmVyIG9mIGNlbGxzIGluIGVhY2ggY2VsbCBncm91cApgYGAKCmBgYHtyfQpDZWxsQ2hhdERCIDwtIENlbGxDaGF0REIuaHVtYW4gIyB1c2UgQ2VsbENoYXREQi5tb3VzZSBpZiBydW5uaW5nIG9uIG1vdXNlIGRhdGEKc2hvd0RhdGFiYXNlQ2F0ZWdvcnkoQ2VsbENoYXREQikKYGBgCgpgYGB7cn0KIyBTaG93IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFiYXNlCmRwbHlyOjpnbGltcHNlKENlbGxDaGF0REIkaW50ZXJhY3Rpb24pCiM+IFJvd3M6IDEsOTM5CiM+IENvbHVtbnM6IDExCiM+ICQgaW50ZXJhY3Rpb25fbmFtZSAgIDxjaHI+ICJUR0ZCMV9UR0ZCUjFfVEdGQlIyIiwgIlRHRkIyX1RHRkJSMV9UR0ZCUjIiLCAiVEdG4oCmCiM+ICQgcGF0aHdheV9uYW1lICAgICAgIDxjaHI+ICJUR0ZiIiwgIlRHRmIiLCAiVEdGYiIsICJUR0ZiIiwgIlRHRmIiLCAiVEdGYiIsICJU4oCmCiM+ICQgbGlnYW5kICAgICAgICAgICAgIDxjaHI+ICJUR0ZCMSIsICJUR0ZCMiIsICJUR0ZCMyIsICJUR0ZCMSIsICJUR0ZCMSIsICJUR0ZC4oCmCiM+ICQgcmVjZXB0b3IgICAgICAgICAgIDxjaHI+ICJUR0ZiUjFfUjIiLCAiVEdGYlIxX1IyIiwgIlRHRmJSMV9SMiIsICJBQ1ZSMUJfVEdG4oCmCiM+ICQgYWdvbmlzdCAgICAgICAgICAgIDxjaHI+ICJUR0ZiIGFnb25pc3QiLCAiVEdGYiBhZ29uaXN0IiwgIlRHRmIgYWdvbmlzdCIsICJU4oCmCiM+ICQgYW50YWdvbmlzdCAgICAgICAgIDxjaHI+ICJUR0ZiIGFudGFnb25pc3QiLCAiVEdGYiBhbnRhZ29uaXN0IiwgIlRHRmIgYW50YWdv4oCmCiM+ICQgY29fQV9yZWNlcHRvciAgICAgIDxjaHI+ICIiLCAiIiwgIiIsICIiLCAiIiwgIiIsICIiLCAiIiwgIiIsICIiLCAiIiwgIiIsICIi4oCmCiM+ICQgY29fSV9yZWNlcHRvciAgICAgIDxjaHI+ICJUR0ZiIGluaGliaXRpb24gcmVjZXB0b3IiLCAiVEdGYiBpbmhpYml0aW9uIHJlY2Vw4oCmCiM+ICQgZXZpZGVuY2UgICAgICAgICAgIDxjaHI+ICJLRUdHOiBoc2EwNDM1MCIsICJLRUdHOiBoc2EwNDM1MCIsICJLRUdHOiBoc2EwNDM14oCmCiM+ICQgYW5ub3RhdGlvbiAgICAgICAgIDxjaHI+ICJTZWNyZXRlZCBTaWduYWxpbmciLCAiU2VjcmV0ZWQgU2lnbmFsaW5nIiwgIlNlY3Jl4oCmCiM+ICQgaW50ZXJhY3Rpb25fbmFtZV8yIDxjaHI+ICJUR0ZCMSAtIChUR0ZCUjErVEdGQlIyKSIsICJUR0ZCMiAtIChUR0ZCUjErVEdGQlIy4oCmCgojIHVzZSBhIHN1YnNldCBvZiBDZWxsQ2hhdERCIGZvciBjZWxsLWNlbGwgY29tbXVuaWNhdGlvbiBhbmFseXNpcwojQ2VsbENoYXREQi51c2UgPC0gc3Vic2V0REIoQ2VsbENoYXREQiwgc2VhcmNoID0gIlNlY3JldGVkIFNpZ25hbGluZyIpICMgdXNlIFNlY3JldGVkIFNpZ25hbGluZwojIHVzZSBhbGwgQ2VsbENoYXREQiBmb3IgY2VsbC1jZWxsIGNvbW11bmljYXRpb24gYW5hbHlzaXMKQ2VsbENoYXREQi51c2UgPC0gQ2VsbENoYXREQiAjIHNpbXBseSB1c2UgdGhlIGRlZmF1bHQgQ2VsbENoYXREQgoKIyBzZXQgdGhlIHVzZWQgZGF0YWJhc2UgaW4gdGhlIG9iamVjdApjZWxsY2hhdEBEQiA8LSBDZWxsQ2hhdERCLnVzZQpgYGAKCmBgYHtyfQpjZWxsY2hhdCA8LSBzdWJzZXREYXRhKGNlbGxjaGF0KSAjIHN1YnNldCB0aGUgZXhwcmVzc2lvbiBkYXRhIG9mIHNpZ25hbGluZyBnZW5lcyBmb3Igc2F2aW5nIGNvbXB1dGF0aW9uIGNvc3QKZnV0dXJlOjpwbGFuKCJtdWx0aXByb2Nlc3MiLCB3b3JrZXJzID0gNCkgIyBkbyBwYXJhbGxlbApgYGAKCmBgYHtyfQpjZWxsY2hhdCA8LSBpZGVudGlmeU92ZXJFeHByZXNzZWRHZW5lcyhjZWxsY2hhdCkKY2VsbGNoYXQgPC0gaWRlbnRpZnlPdmVyRXhwcmVzc2VkSW50ZXJhY3Rpb25zKGNlbGxjaGF0KQpjZWxsY2hhdCA8LSBwcm9qZWN0RGF0YShjZWxsY2hhdCwgUFBJLmh1bWFuKQpgYGAKCmBgYHtyfQojbm90ZSB0cmltIGlzIHJlZmVycmluZyB0byBDZWxsY2hhdHMgbWV0aG9kIGZvciBjYWxjdWxhdGluZyB0aGUgdHJ1bmNhdGVkIG1lYW4sIGRlZmF1bHQgaXMgMC4yNSBtZWFuaW5nIGV4cHJlc3Npb24gd2lsbCBiZSBzZXQgdG8gMCBpZiAyNSUgb3IgbGVzcyBvZiBjZWxscyBvZiBhIGdpdmVuIGNlbGwgdHlwZSBleHByZXNzIHRoZSBsaWdhbmQvcmVjZXB0b3IuIEJ5IGRlZmF1bHQsIEkndmUgY2hhbmdlZCB0aGlzIHRvIDEwJSB0byBhY2NvdW50IGZvciBnZW5lcyBleHByZXNzZWQgaW4gYSBzbWFsbCBwb3J0aW9uIG9mIGNlbGxzLCB0aGF0IGNvdWxkIHN0aWxsIGJlIGJpb2xvZ2ljYWxseSByZWxldmFudC4gSSBiZWxlaXZlIHRoaXMgaXMgbW9yZSBzaW1pbGFyIHRvIENlbGxwaG9uZURCIGN1dCBvZmZzIGFueXdheS4KCmNlbGxjaGF0IDwtIGNvbXB1dGVDb21tdW5Qcm9iKGNlbGxjaGF0LCByYXcudXNlID0gVFJVRSwgdHlwZSA9ICJ0cnVuY2F0ZWRNZWFuIiwgdHJpbSA9IDAuMSkKIyBGaWx0ZXIgb3V0IHRoZSBjZWxsLWNlbGwgY29tbXVuaWNhdGlvbiBpZiB0aGVyZSBhcmUgb25seSBmZXcgbnVtYmVyIG9mIGNlbGxzIGluIGNlcnRhaW4gY2VsbCBncm91cHMKY2VsbGNoYXQgPC0gZmlsdGVyQ29tbXVuaWNhdGlvbihjZWxsY2hhdCwgbWluLmNlbGxzID0gMTApCmBgYAoKCgpFeHBvcnQgcmVzdWx0cyBhcyBhIGRhdGEgZnJhbWUKYGBge3J9CmRmLm5ldCA8LSBzdWJzZXRDb21tdW5pY2F0aW9uKGNlbGxjaGF0KQpoZWFkKGRmLm5ldCkKd3JpdGUuY3N2KGRmLm5ldCwgIi9uZnMvdGVhbTIwNS9hbzE1L01lZ2FndXQvQW5ub3RhdGlvbnNfdjMvZGlzZWFzZV9hbmFseXNpcy9pbnRlcmFjdGlvbnMvcG9vbGVkX2Rpc2Vhc2UucmVtYXBwZWQuYWxsZ2VuZXMuQVBfU0kuY2VsbGNoYXRfb3V0cHV0XzIzMDUyMy5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQpgYGAKCmBgYHtyfQpjZWxsY2hhdCA8LSBjb21wdXRlQ29tbXVuUHJvYlBhdGh3YXkoY2VsbGNoYXQpCmNlbGxjaGF0IDwtIGFnZ3JlZ2F0ZU5ldChjZWxsY2hhdCkKYGBgCgpgYGB7cn0KZ3JvdXBTaXplIDwtIGFzLm51bWVyaWModGFibGUoY2VsbGNoYXRAaWRlbnRzKSkKcGFyKG1mcm93ID0gYygxLDIpLCB4cGQ9VFJVRSkKbmV0VmlzdWFsX2NpcmNsZShjZWxsY2hhdEBuZXQkY291bnQsIHZlcnRleC53ZWlnaHQgPSBncm91cFNpemUsIHdlaWdodC5zY2FsZSA9IFQsIGxhYmVsLmVkZ2U9IEYsIHRpdGxlLm5hbWUgPSAiTnVtYmVyIG9mIGludGVyYWN0aW9ucyIsdmVydGV4LmxhYmVsLmNleCA9IDAuNSkKbmV0VmlzdWFsX2NpcmNsZShjZWxsY2hhdEBuZXQkd2VpZ2h0LCB2ZXJ0ZXgud2VpZ2h0ID0gZ3JvdXBTaXplLCB3ZWlnaHQuc2NhbGUgPSBULCBsYWJlbC5lZGdlPSBGLCB0aXRsZS5uYW1lID0gIkludGVyYWN0aW9uIHdlaWdodHMvc3RyZW5ndGgiLCB2ZXJ0ZXgubGFiZWwuY2V4ID0gMC41KQpgYGAKYGBge3J9CiMgQ29tcHV0ZSB0aGUgbmV0d29yayBjZW50cmFsaXR5IHNjb3JlcwpjZWxsY2hhdCA8LSBuZXRBbmFseXNpc19jb21wdXRlQ2VudHJhbGl0eShjZWxsY2hhdCwgc2xvdC5uYW1lID0gIm5ldFAiKSAjIHRoZSBzbG90ICduZXRQJyBtZWFucyB0aGUgaW5mZXJyZWQgaW50ZXJjZWxsdWxhciBjb21tdW5pY2F0aW9uIG5ldHdvcmsgb2Ygc2lnbmFsaW5nIHBhdGh3YXlzCiMgVmlzdWFsaXplIHRoZSBjb21wdXRlZCBjZW50cmFsaXR5IHNjb3JlcyB1c2luZyBoZWF0bWFwLCBhbGxvd2luZyByZWFkeSBpZGVudGlmaWNhdGlvbiBvZiBtYWpvciBzaWduYWxpbmcgcm9sZXMgb2YgY2VsbCBncm91cHMKI25ldEFuYWx5c2lzX3NpZ25hbGluZ1JvbGVfbmV0d29yayhjZWxsY2hhdCwgc2lnbmFsaW5nID0gcGF0aHdheXMuc2hvdywgd2lkdGggPSA4LCBoZWlnaHQgPSAyLjUsIGZvbnQuc2l6ZSA9IDEwKQpgYGAKCmBgYHtyfQojIFNpZ25hbGluZyByb2xlIGFuYWx5c2lzIG9uIHRoZSBhZ2dyZWdhdGVkIGNlbGwtY2VsbCBjb21tdW5pY2F0aW9uIG5ldHdvcmsgZnJvbSBhbGwgc2lnbmFsaW5nIHBhdGh3YXlzCmh0MSA8LSBuZXRBbmFseXNpc19zaWduYWxpbmdSb2xlX2hlYXRtYXAoY2VsbGNoYXQsIHBhdHRlcm4gPSAib3V0Z29pbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwLCBmb250LnNpemUgPSAzKQpodDIgPC0gbmV0QW5hbHlzaXNfc2lnbmFsaW5nUm9sZV9oZWF0bWFwKGNlbGxjaGF0LCBwYXR0ZXJuID0gImluY29taW5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAxMCwgZm9udC5zaXplID0gMykKcGRmKGZpbGUgPSJhbGxfZ2VuZXNfcGxvdHMvZGlzZWFzZW9ubHkvY2VsbGNoYXRfc2lnbmFsbGluZ19oZWF0bWFwLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9MjApCmh0MSArIGh0MgpkZXYub2ZmKCkKI3BlcnNvbmFsbHkgSSBmaW5kIHRoaXMgcGxvdCBvbmUgb2YgdGhlIG1vc3QgdXNlZnVsIHRvIGxvb2sgYXQgYW4gb3ZlcnZpZXcgb2Ygc2lnbmFsaW5nIHBhdGh3YXlzLCBhbmQgdGhlbiB1c2UgdGhlIG90aGVyIGZ1bmN0aW9ucyB0byBwbG90IHRoZW0gaW4gd2hpY2hldmVyIHdheSBtYWtlcyBzZW5zZQpgYGAKCmBgYHtyfQojc2F2ZSBjZWxsY2hhdCBvYmplY3QKc2F2ZVJEUyhjZWxsY2hhdCwgZmlsZSA9ICIvbmZzL3RlYW0yMDUvYW8xNS9NZWdhZ3V0L0Fubm90YXRpb25zX3YzL2Rpc2Vhc2VfYW5hbHlzaXMvaW50ZXJhY3Rpb25zL3Bvb2xlZF9kaXNlYXNlLnJlbWFwcGVkLmFsbGdlbmVzLkFQX1NJLmNlbGxjaGF0X29iamVjdC5yZHMiKQpgYGAKCgpgYGB7cn0KIyBTaWduYWxpbmcgcm9sZSBhbmFseXNpcyBvbiB0aGUgYWdncmVnYXRlZCBjZWxsLWNlbGwgY29tbXVuaWNhdGlvbiBuZXR3b3JrIGZyb20gYWxsIHNpZ25hbGluZyBwYXRod2F5cwpnZzEgPC0gbmV0QW5hbHlzaXNfc2lnbmFsaW5nUm9sZV9zY2F0dGVyKGNlbGxjaGF0KQpsZXZlbHMoY2VsbGNoYXRAaWRlbnRzKQpnZzEKI3RoaXMgcGxvdCBpcyBoZWxwZnVsIHRvIGxvb2sgYXQgdGhlIG92ZXJhbGwgc2lnbmFsaW5nIHJvbGVzIG9mIGNlbGwgdHlwZXMgKGllLiBhcmUgdGhleSBtb3N0bHkgc2VuZGluZyBzaWduYWxzLCByZWNlaXZpbmcgc2lnbmFscyBvciBhIG1peHR1cmUgb2YgYm90aCkKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9IDEwLCBmaWcud2lkdGg9MTB9Cm1hdCA8LSBjZWxsY2hhdEBuZXQkd2VpZ2h0CnBhcihtZnJvdyA9IGMoMiwyKSwgeHBkPVRSVUUpCmZvciAoaSBpbiAxOm5yb3cobWF0KSkgewogIG1hdDIgPC0gbWF0cml4KDAsIG5yb3cgPSBucm93KG1hdCksIG5jb2wgPSBuY29sKG1hdCksIGRpbW5hbWVzID0gZGltbmFtZXMobWF0KSkKICBtYXQyW2ksIF0gPC0gbWF0W2ksIF0KICBuZXRWaXN1YWxfY2lyY2xlKG1hdDIsIHZlcnRleC53ZWlnaHQgPSBncm91cFNpemUsIHdlaWdodC5zY2FsZSA9IFQsIGVkZ2Uud2VpZ2h0Lm1heCA9IG1heChtYXQpLCB0aXRsZS5uYW1lID0gcm93bmFtZXMobWF0KVtpXSkKfQpgYGAKCmBgYHtyfQpjZWxsY2hhdEBuZXRQJHBhdGh3YXlzCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9MTB9CnBhdGh3YXlzLnNob3cgPC0gYygiTUhDLUlJIikgCiMgSGllcmFyY2h5IHBsb3QKIyBIZXJlIHdlIGRlZmluZSBgdmVydGV4LnJlY2VpdmVgIHNvIHRoYXQgdGhlIGxlZnQgcG9ydGlvbiBvZiB0aGUgaGllcmFyY2h5IHBsb3Qgc2hvd3Mgc2lnbmFsaW5nIHRvIGZpYnJvYmxhc3QgYW5kIHRoZSByaWdodCBwb3J0aW9uIHNob3dzIHNpZ25hbGluZyB0byBpbW11bmUgY2VsbHMgCnZlcnRleC5yZWNlaXZlciA9IHNlcSg0LDgpICMgYSBudW1lcmljIHZlY3Rvci4gCm5ldFZpc3VhbF9hZ2dyZWdhdGUoY2VsbGNoYXQsIHNpZ25hbGluZyA9IHBhdGh3YXlzLnNob3csICB2ZXJ0ZXgucmVjZWl2ZXIgPSB2ZXJ0ZXgucmVjZWl2ZXIpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0xNSwgZmlnLndpZHRoPTIyfQpwYXRod2F5cy5zaG93IDwtIGMoIkNDTCIpIAojIEhlYXRtYXAKcGFyKG1mcm93PWMoMSwxKSkKcGRmKGZpbGUgPSJhbGxfZ2VuZXNfcGxvdHMvZGlzZWFzZW9ubHkvY2VsbGNoYXRfQ0NMaGVhdG1hcC5wZGYiLCB3aWR0aCA9IDIwLCBoZWlnaHQgPTE2KQpuZXRWaXN1YWxfaGVhdG1hcChjZWxsY2hhdCwgc2lnbmFsaW5nID0gcGF0aHdheXMuc2hvdywgY29sb3IuaGVhdG1hcCA9ICJSZWRzIix3aWR0aD01MCxoZWlnaHQ9NTAsZm9udC5zaXplPTYpCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTE1LCBmaWcud2lkdGg9MjJ9CnBhdGh3YXlzLnNob3cgPC0gYygiQ1hDTCIpIAojIEhlYXRtYXAKcGFyKG1mcm93PWMoMSwxKSkKcGRmKGZpbGUgPSJhbGxfZ2VuZXNfcGxvdHMvZGlzZWFzZW9ubHkvY2VsbGNoYXRfQ1hDTGhlYXRtYXAucGRmIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0xNikKbmV0VmlzdWFsX2hlYXRtYXAoY2VsbGNoYXQsIHNpZ25hbGluZyA9IHBhdGh3YXlzLnNob3csIGNvbG9yLmhlYXRtYXAgPSAiUmVkcyIsd2lkdGg9NTAsaGVpZ2h0PTUwLGZvbnQuc2l6ZT02KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD0yMn0KcGF0aHdheXMuc2hvdyA8LSBjKCJNSEMtSUkiKSAKIyBIZWF0bWFwCnBhcihtZnJvdz1jKDEsMSkpCnBkZihmaWxlID0iYWxsX2dlbmVzX3Bsb3RzL2Rpc2Vhc2Vvbmx5L2NlbGxjaGF0X01IQ0lJaGVhdG1hcC5wZGYiLCB3aWR0aCA9IDIwLCBoZWlnaHQgPTE2KQpuZXRWaXN1YWxfaGVhdG1hcChjZWxsY2hhdCwgc2lnbmFsaW5nID0gcGF0aHdheXMuc2hvdywgY29sb3IuaGVhdG1hcCA9ICJSZWRzIix3aWR0aD01MCxoZWlnaHQ9NTAsZm9udC5zaXplPTQpCmBgYAoKCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpwYXIobWZyb3c9YygxLDEpKQpwZGYoZmlsZSA9ImFsbF9nZW5lc19wbG90cy9kaXNlYXNlb25seS9jZWxsY2hhdF9DQ0xjaG9yZC5wZGYiLCB3aWR0aCA9IDIwLCBoZWlnaHQgPTE2KQpuZXRWaXN1YWxfYWdncmVnYXRlKGNlbGxjaGF0LCBzaWduYWxpbmcgPSAnQ0NMJywgbGF5b3V0ID0gImNob3JkIiwgcmVtb3ZlLmlzb2xhdGUgPSBUUlVFLCBzY2FsZT1UUlVFKQpkZXYub2ZmKCkKYGBgCgoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KcGFyKG1mcm93PWMoMSwxKSkKcGRmKGZpbGUgPSJhbGxfZ2VuZXNfcGxvdHMvZGlzZWFzZW9ubHkvY2VsbGNoYXRfQ1hDTGNob3JkLnBkZiIsIHdpZHRoID0gMjAsIGhlaWdodCA9MTYpCm5ldFZpc3VhbF9hZ2dyZWdhdGUoY2VsbGNoYXQsIHNpZ25hbGluZyA9ICdDWENMJywgbGF5b3V0ID0gImNob3JkIiwgcmVtb3ZlLmlzb2xhdGUgPSBUUlVFLCBzY2FsZT1UUlVFKQpkZXYub2ZmKCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpwYXIobWZyb3c9YygxLDEpKQpwZGYoZmlsZSA9ImFsbF9nZW5lc19wbG90cy9kaXNlYXNlb25seS9jZWxsY2hhdF9NSENJSWNob3JkLnBkZiIsIHdpZHRoID0gMjAsIGhlaWdodCA9MTYpCm5ldFZpc3VhbF9hZ2dyZWdhdGUoY2VsbGNoYXQsIHNpZ25hbGluZyA9ICdNSEMtSUknLCBsYXlvdXQgPSAiY2hvcmQiLCByZW1vdmUuaXNvbGF0ZSA9IFRSVUUsIHNjYWxlPVRSVUUpCmRldi5vZmYoKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTE1LCBmaWcud2lkdGg9MTV9CiMgQ2hvcmQgZGlhZ3JhbQojZ3JvdXAuY2VsbFR5cGUgPC0gYyhyZXAoIkZpYnJvIiwgMiksIHJlcCgiQiIsIDMpLCByZXAoIlNNRyIsIDMpKSAjIGdyb3VwaW5nIGNlbGwgY2x1c3RlcnMgaW50byBmaWJyb2JsYXN0LCBEQyBhbmQgVEMgY2VsbHMKI25hbWVzKGdyb3VwLmNlbGxUeXBlKSA8LSBsZXZlbHMoY2VsbGNoYXRAaWRlbnRzKQojbmV0VmlzdWFsX2Nob3JkX2NlbGwoY2VsbGNoYXQsIHNpZ25hbGluZyA9IHBhdGh3YXlzLnNob3csIGdyb3VwID0gZ3JvdXAuY2VsbFR5cGUsIHRpdGxlLm5hbWUgPSBwYXN0ZTAocGF0aHdheXMuc2hvdywgIiBzaWduYWxpbmcgbmV0d29yayIpKQpuZXRWaXN1YWxfY2hvcmRfY2VsbChjZWxsY2hhdCwgc2lnbmFsaW5nID0gcGF0aHdheXMuc2hvdywgdGl0bGUubmFtZSA9IHBhc3RlMChwYXRod2F5cy5zaG93LCAiIHNpZ25hbGluZyBuZXR3b3JrIikpCmBgYAoKYGBge3J9Cm5ldEFuYWx5c2lzX2NvbnRyaWJ1dGlvbihjZWxsY2hhdCwgc2lnbmFsaW5nID0gIkNYQ0wiKQojdG8gZ2V0IGEgY3Vyc29yeSBsb29rIGF0IHdoaWNoIEwtUiBwYWlycyB3aXRoaW4gYSBnaXZlbiBuZXR3b3JrLCBjYW4gYWxzbyBsb29rIGF0IHRoZSBmdWxsIG92ZXJ2aWV3IG9uIHRoZSBjZWxsY2hhdCBkYXRhYmFzZSBodHRwOi8vd3d3LmNlbGxjaGF0Lm9yZy9jZWxsY2hhdGRiLwpgYGAKCgpgYGB7cn0KbmV0QW5hbHlzaXNfY29udHJpYnV0aW9uKGNlbGxjaGF0LCBzaWduYWxpbmcgPSAiQ0NMIikKI3RvIGdldCBhIGN1cnNvcnkgbG9vayBhdCB3aGljaCBMLVIgcGFpcnMgd2l0aGluIGEgZ2l2ZW4gbmV0d29yaywgY2FuIGFsc28gbG9vayBhdCB0aGUgZnVsbCBvdmVydmlldyBvbiB0aGUgY2VsbGNoYXQgZGF0YWJhc2UgaHR0cDovL3d3dy5jZWxsY2hhdC5vcmcvY2VsbGNoYXRkYi8KYGBgCgoKYGBge3J9Cm5ldEFuYWx5c2lzX2NvbnRyaWJ1dGlvbihjZWxsY2hhdCwgc2lnbmFsaW5nID0gIk1IQy1JSSIpCiN0byBnZXQgYSBjdXJzb3J5IGxvb2sgYXQgd2hpY2ggTC1SIHBhaXJzIHdpdGhpbiBhIGdpdmVuIG5ldHdvcmssIGNhbiBhbHNvIGxvb2sgYXQgdGhlIGZ1bGwgb3ZlcnZpZXcgb24gdGhlIGNlbGxjaGF0IGRhdGFiYXNlIGh0dHA6Ly93d3cuY2VsbGNoYXQub3JnL2NlbGxjaGF0ZGIvCmBgYApgYGB7cn0KbmV0QW5hbHlzaXNfY29udHJpYnV0aW9uKGNlbGxjaGF0LCBzaWduYWxpbmcgPSAiVEhCUyIpCiN0byBnZXQgYSBjdXJzb3J5IGxvb2sgYXQgd2hpY2ggTC1SIHBhaXJzIHdpdGhpbiBhIGdpdmVuIG5ldHdvcmssIGNhbiBhbHNvIGxvb2sgYXQgdGhlIGZ1bGwgb3ZlcnZpZXcgb24gdGhlIGNlbGxjaGF0IGRhdGFiYXNlIGh0dHA6Ly93d3cuY2VsbGNoYXQub3JnL2NlbGxjaGF0ZGIvCmBgYAoKYGBge3J9CnBhdGh3YXlzLnNob3cgPSAiQ0NMIgpwYWlyTFIuQ0NMIDwtIGV4dHJhY3RFbnJpY2hlZExSKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBwYXRod2F5cy5zaG93LCBnZW5lTFIucmV0dXJuID0gRkFMU0UpCkxSLnNob3cgPC0gcGFpckxSLkNDTFs2LF0KcGRmKGZpbGUgPSJhbGxfZ2VuZXNfcGxvdHMvZGlzZWFzZW9ubHkvY2VsbGNoYXRfQ0NMbmV0dmlzX2luZGl2aWR1YWwucGRmIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0xNikKbmV0VmlzdWFsX2luZGl2aWR1YWwoY2VsbGNoYXQsIHNpZ25hbGluZyA9IHBhdGh3YXlzLnNob3csIHBhaXJMUi51c2UgPSBMUi5zaG93LCBsYXlvdXQgPSAiY2hvcmQiKQoKYGBgCgpgYGB7cn0KbmV0VmlzdWFsX2FnZ3JlZ2F0ZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gJ0NYQ0wnLCBsYXlvdXQgPSAiY2lyY2xlIikKYGBgCgpgYGB7cn0KbmV0VmlzdWFsX2FnZ3JlZ2F0ZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gJ1NBQScsIGxheW91dCA9ICJjaXJjbGUiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MzB9Cm5ldFZpc3VhbF9idWJibGUoY2VsbGNoYXQsIHNvdXJjZXMudXNlID0gNTcsIHJlbW92ZS5pc29sYXRlID0gRkFMU0UpCmBgYAoKCgpgYGB7ciBmaWcuaGVpZ2h0PTMwfQpwZGYoZmlsZSA9ImFsbF9nZW5lc19wbG90cy9kaXNlYXNlb25seS9jZWxsY2hhdF9NVUM2c291cmNlX25ldHZpc3VhbGJ1YmJsZS5wZGYiLCB3aWR0aCA9IDIwLCBoZWlnaHQgPTMwKQpuZXRWaXN1YWxfYnViYmxlKGNlbGxjaGF0LCBzb3VyY2VzLnVzZSA9IDU3LCByZW1vdmUuaXNvbGF0ZSA9IEZBTFNFKQpgYGAKYGBge3IgZmlnLmhlaWdodD0zMH0KcGRmKGZpbGUgPSJhbGxfZ2VuZXNfcGxvdHMvZGlzZWFzZW9ubHkvY2VsbGNoYXRfTVVDNnRhcmdldF9uZXR2aXN1YWxidWJibGUucGRmIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0zMCkKbmV0VmlzdWFsX2J1YmJsZShjZWxsY2hhdCwgdGFyZ2V0cy51c2UgPSA1NywgcmVtb3ZlLmlzb2xhdGUgPSBGQUxTRSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTQwfQpwZGYoZmlsZSA9ImFsbF9nZW5lc19wbG90cy9kaXNlYXNlb25seS9jZWxsY2hhdF9PcmFsRmlicm9zb3VyY2VfbmV0dmlzdWFsYnViYmxlLnBkZiIsIHdpZHRoID0gMjAsIGhlaWdodCA9NDApCm5ldFZpc3VhbF9idWJibGUoY2VsbGNoYXQsIHNvdXJjZXMudXNlID0gNjMsIHJlbW92ZS5pc29sYXRlID0gRkFMU0UpCmBgYApoYXZlbid0IHJ1biBhbnkgb2YgdGhpcyB5ZXQgLS0+CgoKYGBge3J9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lIDwtIGZ1bmN0aW9uKG9iamVjdCwgc2xvdC5uYW1lID0gIm5ldCIsIGNvbG9yLnVzZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hbGluZyA9IE5VTEwsIHBhaXJMUi51c2UgPSBOVUxMLCBuZXQgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VzLnVzZSA9IE5VTEwsIHRhcmdldHMudXNlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLmNleCA9IDAuOCxzbWFsbC5nYXAgPSAxLCBiaWcuZ2FwID0gMTAsIGFubm90YXRpb25UcmFja0hlaWdodCA9IGMoMC4wMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmsudmlzaWJsZSA9IFRSVUUsIHNjYWxlID0gRkFMU0UsIGRpcmVjdGlvbmFsID0gMSwgbGluay50YXJnZXQucHJvcCA9IFRSVUUsIHJlZHVjZSA9IC0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc3BhcmVuY3kgPSAwLjQsIGxpbmsuYm9yZGVyID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLm5hbWUgPSBOVUxMLCBsZWdlbmQucG9zLnggPSAyMCwgbGVnZW5kLnBvcy55ID0gMjAsIHNob3cubGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNoID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKXsKICBpZiAoIWlzLm51bGwocGFpckxSLnVzZSkpIHsKICAgIGlmICghaXMuZGF0YS5mcmFtZShwYWlyTFIudXNlKSkgewogICAgICBzdG9wKCJwYWlyTFIudXNlIHNob3VsZCBiZSBhIGRhdGEgZnJhbWUgd2l0aCBhIHNpZ25sZSBjb2x1bW4gbmFtZWQgZWl0aGVyICdpbnRlcmFjdGlvbl9uYW1lJyBvciAncGF0aHdheV9uYW1lJyAiKQogICAgfSBlbHNlIGlmICgicGF0aHdheV9uYW1lIiAlaW4lIGNvbG5hbWVzKHBhaXJMUi51c2UpKSB7CiAgICAgIG1lc3NhZ2UoInNsb3QubmFtZSBpcyBzZXQgdG8gYmUgJ25ldFAnIHdoZW4gcGFpckxSLnVzZSBjb250YWlucyBzaWduYWxpbmcgcGF0aHdheXMiKQogICAgICBzbG90Lm5hbWUgPSAibmV0UCIKICAgIH0KICB9CgogIGlmICghaXMubnVsbChwYWlyTFIudXNlKSAmICFpcy5udWxsKHNpZ25hbGluZykpIHsKICAgIHN0b3AoIlBsZWFzZSBkbyBub3QgYXNzaWduIHZhbHVlcyB0byAnc2lnbmFsaW5nJyB3aGVuIHVzaW5nICdwYWlyTFIudXNlJyIpCiAgfQoKICBpZiAoaXMubnVsbChuZXQpKSB7CiAgICBwcm9iIDwtIHNsb3Qob2JqZWN0LCAibmV0IikkcHJvYgogICAgcHZhbCA8LSBzbG90KG9iamVjdCwgIm5ldCIpJHB2YWwKICAgIHByb2JbcHZhbCA+IHRocmVzaF0gPC0gMAogICAgbmV0IDwtIHJlc2hhcGUyOjptZWx0KHByb2IsIHZhbHVlLm5hbWUgPSAicHJvYiIpCiAgICBjb2xuYW1lcyhuZXQpWzE6M10gPC0gYygic291cmNlIiwidGFyZ2V0IiwiaW50ZXJhY3Rpb25fbmFtZSIpCgogICAgcGFpckxSID0gZHBseXI6OnNlbGVjdChvYmplY3RATFIkTFJzaWcsIGMoImludGVyYWN0aW9uX25hbWVfMiIsICJwYXRod2F5X25hbWUiLCAgImxpZ2FuZCIsICAicmVjZXB0b3IiICwiYW5ub3RhdGlvbiIsImV2aWRlbmNlIikpCiAgICBpZHggPC0gbWF0Y2gobmV0JGludGVyYWN0aW9uX25hbWUsIHJvd25hbWVzKHBhaXJMUikpCiAgICB0ZW1wIDwtIHBhaXJMUltpZHgsXQogICAgbmV0IDwtIGNiaW5kKG5ldCwgdGVtcCkKICB9CgogIGlmICghaXMubnVsbChzaWduYWxpbmcpKSB7CiAgICBwYWlyTFIudXNlIDwtIGRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6bGVuZ3RoKHNpZ25hbGluZykpIHsKICAgICAgcGFpckxSLnVzZS5pIDwtIHNlYXJjaFBhaXIoc2lnbmFsaW5nID0gc2lnbmFsaW5nW2ldLCBwYWlyTFIudXNlID0gb2JqZWN0QExSJExSc2lnLCBrZXkgPSAicGF0aHdheV9uYW1lIiwgbWF0Y2hpbmcuZXhhY3QgPSBULCBwYWlyLm9ubHkgPSBUKQogICAgICBwYWlyTFIudXNlIDwtIHJiaW5kKHBhaXJMUi51c2UsIHBhaXJMUi51c2UuaSkKICAgIH0KICB9CgogIGlmICghaXMubnVsbChwYWlyTFIudXNlKSl7CiAgICBpZiAoImludGVyYWN0aW9uX25hbWUiICVpbiUgY29sbmFtZXMocGFpckxSLnVzZSkpIHsKICAgICAgbmV0IDwtIHN1YnNldChuZXQsaW50ZXJhY3Rpb25fbmFtZSAlaW4lIHBhaXJMUi51c2UkaW50ZXJhY3Rpb25fbmFtZSkKICAgIH0gZWxzZSBpZiAoInBhdGh3YXlfbmFtZSIgJWluJSBjb2xuYW1lcyhwYWlyTFIudXNlKSkgewogICAgICBuZXQgPC0gc3Vic2V0KG5ldCwgcGF0aHdheV9uYW1lICVpbiUgYXMuY2hhcmFjdGVyKHBhaXJMUi51c2UkcGF0aHdheV9uYW1lKSkKICAgIH0KICB9CgogIGlmIChzbG90Lm5hbWUgPT0gIm5ldFAiKSB7CiAgICBuZXQgPC0gZHBseXI6OnNlbGVjdChuZXQsIGMoInNvdXJjZSIsInRhcmdldCIsInBhdGh3YXlfbmFtZSIsInByb2IiKSkKICAgIG5ldCRzb3VyY2VfdGFyZ2V0IDwtIHBhc3RlKG5ldCRzb3VyY2UsIG5ldCR0YXJnZXQsIHNlcCA9ICJzb3VyY2VUb3RhcmdldCIpCiAgICBuZXQgPC0gbmV0ICU+JSBkcGx5cjo6Z3JvdXBfYnkoc291cmNlX3RhcmdldCwgcGF0aHdheV9uYW1lKSAlPiUgZHBseXI6OnN1bW1hcml6ZShwcm9iID0gc3VtKHByb2IpKQogICAgYSA8LSBzdHJpbmdyOjpzdHJfc3BsaXQobmV0JHNvdXJjZV90YXJnZXQsICJzb3VyY2VUb3RhcmdldCIsIHNpbXBsaWZ5ID0gVCkKICAgIG5ldCRzb3VyY2UgPC0gYXMuY2hhcmFjdGVyKGFbLCAxXSkKICAgIG5ldCR0YXJnZXQgPC0gYXMuY2hhcmFjdGVyKGFbLCAyXSkKICAgIG5ldCRsaWdhbmQgPC0gbmV0JHBhdGh3YXlfbmFtZQogICAgbmV0JHJlY2VwdG9yIDwtICIgIgogIH0KCiAgIyBrZWVwIHRoZSBpbnRlcmFjdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHNvdXJjZXMgYW5kIHRhcmdldHMgb2YgaW50ZXJlc3QKICBpZiAoIWlzLm51bGwoc291cmNlcy51c2UpKXsKICAgIGlmIChpcy5udW1lcmljKHNvdXJjZXMudXNlKSkgewogICAgICBzb3VyY2VzLnVzZSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbc291cmNlcy51c2VdCiAgICB9CiAgICBuZXQgPC0gc3Vic2V0KG5ldCwgc291cmNlICVpbiUgc291cmNlcy51c2UpCiAgfSBlbHNlIHsKICAgIHNvdXJjZXMudXNlIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKQogIH0KICBpZiAoIWlzLm51bGwodGFyZ2V0cy51c2UpKXsKICAgIGlmIChpcy5udW1lcmljKHRhcmdldHMudXNlKSkgewogICAgICB0YXJnZXRzLnVzZSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbdGFyZ2V0cy51c2VdCiAgICB9CiAgICBuZXQgPC0gc3Vic2V0KG5ldCwgdGFyZ2V0ICVpbiUgdGFyZ2V0cy51c2UpCiAgfSBlbHNlIHsKICAgIHRhcmdldHMudXNlIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKQogIH0KICAjIHJlbW92ZSB0aGUgaW50ZXJhY3Rpb25zIHdpdGggemVybyB2YWx1ZXMKICBkZiA8LSBzdWJzZXQobmV0LCBwcm9iID4gMCkKCiAgaWYgKG5yb3coZGYpID09IDApIHsKICAgIHN0b3AoIk5vIHNpZ25hbGluZyBsaW5rcyBhcmUgaW5mZXJyZWQhICIpCiAgfQoKICBpZiAobGVuZ3RoKHVuaXF1ZShuZXQkbGlnYW5kKSkgPT0gMSkgewogICAgbWVzc2FnZSgiWW91IG1heSB0cnkgdGhlIGZ1bmN0aW9uIGBuZXRWaXN1YWxfY2hvcmRfY2VsbGAgZm9yIHZpc3VhbGl6aW5nIGluZGl2aWR1YWwgc2lnbmFsaW5nIHBhdGh3YXkiKQogIH0KCiAgZGYkaWQgPC0gMTpucm93KGRmKQogICMgZGVhbCB3aXRoIGR1cGxpY2F0ZWQgc2VjdG9yIG5hbWVzCiAgbGlnYW5kLnVuaSA8LSB1bmlxdWUoZGYkbGlnYW5kKQogIGZvciAoaSBpbiAxOmxlbmd0aChsaWdhbmQudW5pKSkgewogICAgZGYuaSA8LSBkZltkZiRsaWdhbmQgPT0gbGlnYW5kLnVuaVtpXSwgXQogICAgc291cmNlLnVuaSA8LSB1bmlxdWUoZGYuaSRzb3VyY2UpCiAgICBmb3IgKGogaW4gMTpsZW5ndGgoc291cmNlLnVuaSkpIHsKICAgICAgZGYuaS5qIDwtIGRmLmlbZGYuaSRzb3VyY2UgPT0gc291cmNlLnVuaVtqXSwgXQogICAgICBkZi5pLmokbGlnYW5kIDwtIHBhc3RlMChkZi5pLmokbGlnYW5kLCBwYXN0ZShyZXAoJyAnLGotMSksY29sbGFwc2UgPSAnJykpCiAgICAgIGRmJGxpZ2FuZFtkZiRpZCAlaW4lIGRmLmkuaiRpZF0gPC0gZGYuaS5qJGxpZ2FuZAogICAgfQogIH0KICByZWNlcHRvci51bmkgPC0gdW5pcXVlKGRmJHJlY2VwdG9yKQogIGZvciAoaSBpbiAxOmxlbmd0aChyZWNlcHRvci51bmkpKSB7CiAgICBkZi5pIDwtIGRmW2RmJHJlY2VwdG9yID09IHJlY2VwdG9yLnVuaVtpXSwgXQogICAgdGFyZ2V0LnVuaSA8LSB1bmlxdWUoZGYuaSR0YXJnZXQpCiAgICBmb3IgKGogaW4gMTpsZW5ndGgodGFyZ2V0LnVuaSkpIHsKICAgICAgZGYuaS5qIDwtIGRmLmlbZGYuaSR0YXJnZXQgPT0gdGFyZ2V0LnVuaVtqXSwgXQogICAgICBkZi5pLmokcmVjZXB0b3IgPC0gcGFzdGUwKGRmLmkuaiRyZWNlcHRvciwgcGFzdGUocmVwKCcgJyxqLTEpLGNvbGxhcHNlID0gJycpKQogICAgICBkZiRyZWNlcHRvcltkZiRpZCAlaW4lIGRmLmkuaiRpZF0gPC0gZGYuaS5qJHJlY2VwdG9yCiAgICB9CiAgfQoKICBjZWxsLm9yZGVyLnNvdXJjZXMgPC0gbGV2ZWxzKG9iamVjdEBpZGVudHMpW2xldmVscyhvYmplY3RAaWRlbnRzKSAlaW4lIHNvdXJjZXMudXNlXQogIGNlbGwub3JkZXIudGFyZ2V0cyA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbbGV2ZWxzKG9iamVjdEBpZGVudHMpICVpbiUgdGFyZ2V0cy51c2VdCgogIGRmJHNvdXJjZSA8LSBmYWN0b3IoZGYkc291cmNlLCBsZXZlbHMgPSBjZWxsLm9yZGVyLnNvdXJjZXMpCiAgZGYkdGFyZ2V0IDwtIGZhY3RvcihkZiR0YXJnZXQsIGxldmVscyA9IGNlbGwub3JkZXIudGFyZ2V0cykKICAjIGRmLm9yZGVyZWQuc291cmNlIDwtIGRmW3dpdGgoZGYsIG9yZGVyKHNvdXJjZSwgdGFyZ2V0LCAtcHJvYikpLCBdCiAgIyBkZi5vcmRlcmVkLnRhcmdldCA8LSBkZlt3aXRoKGRmLCBvcmRlcih0YXJnZXQsIHNvdXJjZSwgLXByb2IpKSwgXQogIGRmLm9yZGVyZWQuc291cmNlIDwtIGRmW3dpdGgoZGYsIG9yZGVyKHNvdXJjZSwgLXByb2IpKSwgXQogIGRmLm9yZGVyZWQudGFyZ2V0IDwtIGRmW3dpdGgoZGYsIG9yZGVyKHRhcmdldCwgLXByb2IpKSwgXQoKICBvcmRlci5zb3VyY2UgPC0gdW5pcXVlKGRmLm9yZGVyZWQuc291cmNlWyAsYygnbGlnYW5kJywnc291cmNlJyldKQogIG9yZGVyLnRhcmdldCA8LSB1bmlxdWUoZGYub3JkZXJlZC50YXJnZXRbICxjKCdyZWNlcHRvcicsJ3RhcmdldCcpXSkKCiAgIyBkZWZpbmUgc2VjdG9yIG9yZGVyCiAgb3JkZXIuc2VjdG9yIDwtIGMob3JkZXIuc291cmNlJGxpZ2FuZCwgb3JkZXIudGFyZ2V0JHJlY2VwdG9yKQoKICAjIGRlZmluZSBjZWxsIHR5cGUgY29sb3IKICBpZiAoaXMubnVsbChjb2xvci51c2UpKXsKICAgIGNvbG9yLnVzZSA9IHNjUGFsZXR0ZShubGV2ZWxzKG9iamVjdEBpZGVudHMpKQogICAgbmFtZXMoY29sb3IudXNlKSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cykKICAgIGNvbG9yLnVzZSA8LSBjb2xvci51c2VbbGV2ZWxzKG9iamVjdEBpZGVudHMpICVpbiUgYXMuY2hhcmFjdGVyKHVuaW9uKGRmJHNvdXJjZSxkZiR0YXJnZXQpKV0KICB9IGVsc2UgaWYgKGlzLm51bGwobmFtZXMoY29sb3IudXNlKSkpIHsKICAgIG5hbWVzKGNvbG9yLnVzZSkgPC0gbGV2ZWxzKG9iamVjdEBpZGVudHMpCiAgICBjb2xvci51c2UgPC0gY29sb3IudXNlW2xldmVscyhvYmplY3RAaWRlbnRzKSAlaW4lIGFzLmNoYXJhY3Rlcih1bmlvbihkZiRzb3VyY2UsZGYkdGFyZ2V0KSldCiAgfQoKICAjIGRlZmluZSBlZGdlIGNvbG9yCiAgZWRnZS5jb2xvciA8LSBjb2xvci51c2VbYXMuY2hhcmFjdGVyKGRmLm9yZGVyZWQuc291cmNlJHNvdXJjZSldCiAgbmFtZXMoZWRnZS5jb2xvcikgPC0gYXMuY2hhcmFjdGVyKGRmLm9yZGVyZWQuc291cmNlJHNvdXJjZSkKCiAgIyBkZWZpbmUgZ3JpZCBjb2xvcnMKICBncmlkLmNvbC5saWdhbmQgPC0gY29sb3IudXNlW2FzLmNoYXJhY3RlcihvcmRlci5zb3VyY2Ukc291cmNlKV0KICBuYW1lcyhncmlkLmNvbC5saWdhbmQpIDwtIGFzLmNoYXJhY3RlcihvcmRlci5zb3VyY2Ukc291cmNlKQogIGdyaWQuY29sLnJlY2VwdG9yIDwtIGNvbG9yLnVzZVthcy5jaGFyYWN0ZXIob3JkZXIudGFyZ2V0JHRhcmdldCldCiAgbmFtZXMoZ3JpZC5jb2wucmVjZXB0b3IpIDwtIGFzLmNoYXJhY3RlcihvcmRlci50YXJnZXQkdGFyZ2V0KQogIGdyaWQuY29sIDwtIGMoYXMuY2hhcmFjdGVyKGdyaWQuY29sLmxpZ2FuZCksIGFzLmNoYXJhY3RlcihncmlkLmNvbC5yZWNlcHRvcikpCiAgbmFtZXMoZ3JpZC5jb2wpIDwtIG9yZGVyLnNlY3RvcgoKICBkZi5wbG90IDwtIGRmLm9yZGVyZWQuc291cmNlWyAsYygnbGlnYW5kJywncmVjZXB0b3InLCdwcm9iJyldCgogIGlmIChkaXJlY3Rpb25hbCA9PSAyKSB7CiAgICBsaW5rLmFyci50eXBlID0gInRyaWFuZ2xlIgogIH0gZWxzZSB7CiAgICBsaW5rLmFyci50eXBlID0gImJpZy5hcnJvdyIKICB9CiAgY2lyY29zLmNsZWFyKCkKICBjaG9yZERpYWdyYW0oZGYucGxvdCwKICAgICAgICAgICAgICAgb3JkZXIgPSBvcmRlci5zZWN0b3IsCiAgICAgICAgICAgICAgIGNvbCA9IGVkZ2UuY29sb3IsCiAgICAgICAgICAgICAgIGdyaWQuY29sID0gZ3JpZC5jb2wsCiAgICAgICAgICAgICAgIHRyYW5zcGFyZW5jeSA9IHRyYW5zcGFyZW5jeSwKICAgICAgICAgICAgICAgbGluay5ib3JkZXIgPSBsaW5rLmJvcmRlciwKICAgICAgICAgICAgICAgZGlyZWN0aW9uYWwgPSBkaXJlY3Rpb25hbCwKICAgICAgICAgICAgICAgZGlyZWN0aW9uLnR5cGUgPSBjKCJkaWZmSGVpZ2h0IiwiYXJyb3dzIiksCiAgICAgICAgICAgICAgIGxpbmsuYXJyLnR5cGUgPSBsaW5rLmFyci50eXBlLAogICAgICAgICAgICAgICBhbm5vdGF0aW9uVHJhY2sgPSAiZ3JpZCIsCiAgICAgICAgICAgICAgIGFubm90YXRpb25UcmFja0hlaWdodCA9IGFubm90YXRpb25UcmFja0hlaWdodCwKICAgICAgICAgICAgICAgcHJlQWxsb2NhdGVUcmFja3MgPSBsaXN0KHRyYWNrLmhlaWdodCA9IG1heChzdHJ3aWR0aChvcmRlci5zZWN0b3IpKSksCiAgICAgICAgICAgICAgIHNtYWxsLmdhcCA9IHNtYWxsLmdhcCwKICAgICAgICAgICAgICAgYmlnLmdhcCA9IGJpZy5nYXAsCiAgICAgICAgICAgICAgIGxpbmsudmlzaWJsZSA9IGxpbmsudmlzaWJsZSwKICAgICAgICAgICAgICAgc2NhbGUgPSBzY2FsZSwKICAgICAgICAgICAgICAgbGluay50YXJnZXQucHJvcCA9IGxpbmsudGFyZ2V0LnByb3AsCiAgICAgICAgICAgICAgIHJlZHVjZSA9IHJlZHVjZSwKICAgICAgICAgICAgICAgLi4uKQoKICBjaXJjb3MudHJhY2sodHJhY2suaW5kZXggPSAxLCBwYW5lbC5mdW4gPSBmdW5jdGlvbih4LCB5KSB7CiAgICB4bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4bGltIikKICAgIHhwbG90ID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4cGxvdCIpCiAgICB5bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ5bGltIikKICAgIHNlY3Rvci5uYW1lID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJzZWN0b3IuaW5kZXgiKQogICAgY2lyY29zLnRleHQobWVhbih4bGltKSwgeWxpbVsxXSwgc2VjdG9yLm5hbWUsIGZhY2luZyA9ICJiZW5kaW5nIiwgbmljZUZhY2luZyA9IFRSVUUsIGFkaj1jKDAuNSwwLjAxKSxjZXggPSBsYWIuY2V4KQogIH0sIGJnLmJvcmRlciA9IE5BKQoKCiAgIyBodHRwczovL2pva2VyZ29vLmdpdGh1Yi5pby9jaXJjbGl6ZV9ib29rL2Jvb2svbGVnZW5kcy5odG1sCiAgaWYgKHNob3cubGVnZW5kKSB7CiAgICBsZ2QgPC0gQ29tcGxleEhlYXRtYXA6OkxlZ2VuZChhdCA9IG5hbWVzKGNvbG9yLnVzZSksIHR5cGUgPSAiZ3JpZCIsIGxlZ2VuZF9ncCA9IGdyaWQ6OmdwYXIoZmlsbCA9IGNvbG9yLnVzZSksIHRpdGxlID0gIkNlbGwgU3RhdGUiKQogICAgQ29tcGxleEhlYXRtYXA6OmRyYXcobGdkLCB4ID0gdW5pdCgxLCAibnBjIiktdW5pdChsZWdlbmQucG9zLngsICJtbSIpLCB5ID0gdW5pdChsZWdlbmQucG9zLnksICJtbSIpLCBqdXN0ID0gYygicmlnaHQiLCAiYm90dG9tIikpCiAgfQoKICBjaXJjb3MuY2xlYXIoKQogIGlmKCFpcy5udWxsKHRpdGxlLm5hbWUpKXsKICAgIHRleHQoLTAsIDEuMDIsIHRpdGxlLm5hbWUsIGNleD0xKQogIH0KICBnZyA8LSByZWNvcmRQbG90KCkKICByZXR1cm4oZ2cpCn0KYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTE1LGZpZy53aWR0aD0xNX0KbmV0VmlzdWFsX2Nob3JkX2dlbmUoY2VsbGNoYXQsIHNpZ25hbGluZyA9IGMoIlNBQSIpLGxlZ2VuZC5wb3MueCA9IDgsIHNjYWxlPUZBTFNFKSMsIHNvdXJjZXMudXNlID0gYygxLDIsMyw0LDUsNiw3KSwgdGFyZ2V0cy51c2UgPSBjKDEsMiwzLDQsNSw2LDcpLCBsYWIuY2V4PTEsICBjb2xvci51c2UgPSBjKCcjQ0Q2NjAwJywgJyNGRjhDMDAnLCAnI0NEMDBDRCcsJyMwMDAwRUUnLCAnIzhGQkM4RicsJyNDMUZGQzEnLCcjMjI4QjIyJykpIApgYGAKYGBge3J9CmNvbG91cnMgPSBjKCcjZGI5NjAyJywjICAgJ0JfR0NfSSc6CiAnI2UyZDEzOCcsIyAgICdCX0dDX0knOgonI2EzM2MyMicsIyAgICdCX21lbW9yeSc6CiAgJyM5YjAzMTknLCMgJ0JfbmFpdmUnOgogICcjZjc2YzU2JywjICdCX3BsYXNtYV9JZ0ExJzoKICAnI2Q2NTU4ZCcsIyAnQl9wbGFzbWFfSWdBMic6CicjNjMyZjE3JywjICAgJ0JfcGxhc21hX0lnRyc6CiAgJyNjNjZkMzEnLCMgJ0JfcGxhc21hX0lnTSc6CiAgJyM5ZTUzZGInLCMgJ0JfcGxhc21hYmxhc3QnOgogICcjOGE0NjgyJywjICdCX3ByZUInOgonI2QzNDc5NCcsIyAgICdCX3Byb0InOgonIzM5OTk3YycsIyAgICdCRVNUNF9lbnRlcm9jeXRlX2NvbG9ub2N5dGUnOgonI2JkNzg3OScsIyAgICdDcnlwdF9maWJyb2JsYXN0X1BJMTYnOgonIzhjNTQzZicsIyAgICdEQ19jREMxJzoKJyNjZmRiNjUnLCMgICAnRENfY0RDMic6CicjYzdhNjQyJywjICAgJ0RDX2xhbmdlcmhhbnMnOgonI2U2YTUxOScsIyAgICdEQ19taWdyYXRvcnknOgonI2JkYjE5NycsIyAgICdEQ19wREMnOgonI2ZhNmU2ZScsIyAgICdFQ19hcnRlcmlhbF8xJzoKJyNjYTYwOTInLCMgICAnRUNfYXJ0ZXJpYWxfMic6CicjODU1ZjlhJywjICAgJ0VDX2NhcGlsbGFyeSc6CicjZmFjMDZlJywjICAgJ0VDX2N5Y2xpbmcnOgonIzk5OTk5OScsIyAgICdFQ19seW1waGF0aWMnOgonIzJhNDg1OCcsIyAnRUNfdmVub3VzJzoKJyNEQkE1MDcnLCMgICAnRW50ZXJpY19uZXVyYWxfY3Jlc3RfY3ljbGluZyc6CicjZTFiNWU2JywjICAgICAnRW50ZXJvY3l0ZSc6CicjNjhiN2ZjJywjICAgJ0VudGVyb2VuZG9jcmluZSc6CiAgJyM4YjRlYmEnLCMgJ0Vvc2lub3BoaWwvYmFzb3BoaWwnOgogICcjYzkyNGI5JywjICdFcGl0aGVsaWFsX3N0ZW0nOgogICcjMGU1MzljJywjICdFcnl0aHJvY3l0ZXMnOgogICcjZjBjMTM0JywjICdGaWJyb2JsYXN0X3JldGljdWxhcic6CicjZjA5ODJjJywjICAgJ0ZvbGxpY3VsYXJfREMnOgonIzNmYWZiNScsIyAgICdnZFQnOgonIzI2ZGFmMicsIyAgICAgJ2dkVF9uYWl2ZSc6CicjOEVDN0QyJywjICAgJ0dsaWFsXzEnOgonIzBENjk4NicsIyAgICdHbGlhbF8yJzoKJyMwNTMyNDAnLCMgICAnR2xpYWxfMyc6CicjYThjNTQ1JywjICAgJ0dsaWFsL0VudGVyaWNfbmV1cmFsX2NyZXN0JzoKJyM2Yzk5MzknLCMgICAgICdHb2JsZXQnOgonI2QxZDE0ZicsIyAnR29ibGV0X2N5Y2xpbmcnOgonI2U5ZjdhZCcsIyAnR29ibGV0X3Byb2dlbml0b3InOgonIzc3OGMwMCcsIyAgICAgJ0lMQzMnOgonI0FBQzc4OScsIyAgICdJbW11bmVfcmVjcnVpdGluZ19wZXJpY3l0ZSc6CicjZTk1ZTUwJywjICAgJ0xhbWluYV9wcm9wcmlhX2ZpYnJvYmxhc3RfQURBTURFQzEnOgonIzQ4NjYyNicsIyAnTWFjcm9waGFnZSc6CicjY2FmOWNmJywjICAgJ01hY3JvcGhhZ2VfQ0Q1TCc6CicjOGZkOWQwJywjICAgJ01hY3JvcGhhZ2VfTFlWRTEnOgonI2E1ZjAwMicsIyAgICdNYWNyb3BoYWdlX01NUDknOgonIzQyYzdhYycsIyAgICdNYWNyb3BoYWdlX1RSRU0yJzoKJyMyMWI3OTYnLCMgICAgICdNQUlUJzoKJyM4MjZlOTEnLCMgICAnTWFzdCc6CicjYzczMGFhJywjICAgJ01lZ2FrYXJ5b2N5dGUvcGxhdGVsZXQnOgonIzhGNjU5MicsIyAgICdNZXNvdGhlbGl1bSc6CicjZTU1Yjg1JywjICAgJ01pY3JvZm9sZCc6CicjMmE0OTdhJywjICAgJ01vbm8vbmV1dHJvcGhpbF9NUE8nOgonIzViYWYwNycsIyAgICdNb25vY3l0ZSc6CicjZjdiMzdjJywjICAgJ011Y291c19nbGFuZF9uZWNrJzoKJyNDQ0FFOTEnLCMgICAnTXlvZmlicm9ibGFzdCc6CicjYzUwNjM3JywjICAgJ05ldXJvYmxhc3QnOgonIzBjMWUwZScsIyAgICdOS19DRDE2JzoKJyMzZjhjMDgnLCMgICAnTktfQ0Q1NmJyaWdodCc6CicjNjNBMEMwJywjICAgICAnT2Vzb3BoYWd1c19maWJyb2JsYXN0JzoKJyMzMDMyNjcnLCMgICAnT3JhbF9tdWNvc2FfZmlicm9ibGFzdCc6CicjNzk1MDhmJywjICAgJ1BhbmV0aCc6CicjNDM3MzU2JywjICAgICAnUGVyaWN5dGUnOgonIzUyMmUyNScsIyAgICdSZWN0dW1fZmlicm9ibGFzdCc6CicjZDliNzRhJywjICAgJ1N1cmZhY2VfZm92ZW9sYXInOgonI2MyNjBmZicsIyAgICdUL05LX2N5Y2xpbmcnOgonI2I4NWYxYycsIyAgICdUQSc6CicjNWUwYjMwJywjICdUZmgnOgonIzVlM2M1NScsIyAgICdUZmhfbmFpdmUnOgonIzljNTNiYycsIyAgICAgJ1RuYWl2ZS9jbV9DRDQnOgonIzVjYTRjZScsIyAgICdUbmFpdmUvY21fQ0Q4JzoKJyNmOTgyNjEnLCMgICAgICdUcmVnJzoKJyNlNWM1MTAnLCMgJ1RyZWdfSUwxMCc6CicjODEwN2VkJywjICAgJ1RybV9DRDQnOgonIzI4NDRjMScsIyAgICdUcm1fQ0Q4JzoKJyMxZTA5M2YnLCMgICAnVHJtX1RoMTcnOgonIzI1NmI4NycsIyAgICdUcm0vZW1fQ0Q4JzoKJyM5ZDlkZmYnLCMgICAnVHVmdCc6CicjMUU0MTQ3JywjICAgJ1Zhc2N1bGFyX3Ntb290aF9tdXNjbGUnOgonI2Q2NDU4MicjICAgJ1ZpbGx1c19maWJyb2JsYXN0X0YzJzoKKQpgYGAKCgoKCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTV9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJTQUEiKSwgbGVnZW5kLnBvcy54ID0gOCwgc2NhbGU9RkFMU0Usc291cmNlcy51c2UgPSBjKDMwLDMyLDU2LDU3LDYzKSwgdGFyZ2V0cy51c2UgPSBjKDMwLDMyLDU2LDU3LDYzKSwgbGFiLmNleD0xLGNvbG9yLnVzZSA9IGNvbG91cnMpIApgYGAKYGBge3J9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lIDwtIGZ1bmN0aW9uKG9iamVjdCwgc2xvdC5uYW1lID0gIm5ldCIsIGNvbG9yLnVzZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hbGluZyA9IE5VTEwsIHBhaXJMUi51c2UgPSBOVUxMLCBuZXQgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VzLnVzZSA9IE5VTEwsIHRhcmdldHMudXNlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLmNleCA9IDAuOCxzbWFsbC5nYXAgPSAxLCBiaWcuZ2FwID0gMTAsIGFubm90YXRpb25UcmFja0hlaWdodCA9IGMoMC4wMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmsudmlzaWJsZSA9IFRSVUUsIHNjYWxlID0gRkFMU0UsIGRpcmVjdGlvbmFsID0gMSwgbGluay50YXJnZXQucHJvcCA9IFRSVUUsIHJlZHVjZSA9IC0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc3BhcmVuY3kgPSAwLjQsIGxpbmsuYm9yZGVyID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLm5hbWUgPSBOVUxMLCBsZWdlbmQucG9zLnggPSAyMCwgbGVnZW5kLnBvcy55ID0gMjAsIHNob3cubGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNoID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKXsKICBpZiAoIWlzLm51bGwocGFpckxSLnVzZSkpIHsKICAgIGlmICghaXMuZGF0YS5mcmFtZShwYWlyTFIudXNlKSkgewogICAgICBzdG9wKCJwYWlyTFIudXNlIHNob3VsZCBiZSBhIGRhdGEgZnJhbWUgd2l0aCBhIHNpZ25sZSBjb2x1bW4gbmFtZWQgZWl0aGVyICdpbnRlcmFjdGlvbl9uYW1lJyBvciAncGF0aHdheV9uYW1lJyAiKQogICAgfSBlbHNlIGlmICgicGF0aHdheV9uYW1lIiAlaW4lIGNvbG5hbWVzKHBhaXJMUi51c2UpKSB7CiAgICAgIG1lc3NhZ2UoInNsb3QubmFtZSBpcyBzZXQgdG8gYmUgJ25ldFAnIHdoZW4gcGFpckxSLnVzZSBjb250YWlucyBzaWduYWxpbmcgcGF0aHdheXMiKQogICAgICBzbG90Lm5hbWUgPSAibmV0UCIKICAgIH0KICB9CgogIGlmICghaXMubnVsbChwYWlyTFIudXNlKSAmICFpcy5udWxsKHNpZ25hbGluZykpIHsKICAgIHN0b3AoIlBsZWFzZSBkbyBub3QgYXNzaWduIHZhbHVlcyB0byAnc2lnbmFsaW5nJyB3aGVuIHVzaW5nICdwYWlyTFIudXNlJyIpCiAgfQoKICBpZiAoaXMubnVsbChuZXQpKSB7CiAgICBwcm9iIDwtIHNsb3Qob2JqZWN0LCAibmV0IikkcHJvYgogICAgcHZhbCA8LSBzbG90KG9iamVjdCwgIm5ldCIpJHB2YWwKICAgIHByb2JbcHZhbCA+IHRocmVzaF0gPC0gMAogICAgbmV0IDwtIHJlc2hhcGUyOjptZWx0KHByb2IsIHZhbHVlLm5hbWUgPSAicHJvYiIpCiAgICBjb2xuYW1lcyhuZXQpWzE6M10gPC0gYygic291cmNlIiwidGFyZ2V0IiwiaW50ZXJhY3Rpb25fbmFtZSIpCgogICAgcGFpckxSID0gZHBseXI6OnNlbGVjdChvYmplY3RATFIkTFJzaWcsIGMoImludGVyYWN0aW9uX25hbWVfMiIsICJwYXRod2F5X25hbWUiLCAgImxpZ2FuZCIsICAicmVjZXB0b3IiICwiYW5ub3RhdGlvbiIsImV2aWRlbmNlIikpCiAgICBpZHggPC0gbWF0Y2gobmV0JGludGVyYWN0aW9uX25hbWUsIHJvd25hbWVzKHBhaXJMUikpCiAgICB0ZW1wIDwtIHBhaXJMUltpZHgsXQogICAgbmV0IDwtIGNiaW5kKG5ldCwgdGVtcCkKICB9CgogIGlmICghaXMubnVsbChzaWduYWxpbmcpKSB7CiAgICBwYWlyTFIudXNlIDwtIGRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6bGVuZ3RoKHNpZ25hbGluZykpIHsKICAgICAgcGFpckxSLnVzZS5pIDwtIHNlYXJjaFBhaXIoc2lnbmFsaW5nID0gc2lnbmFsaW5nW2ldLCBwYWlyTFIudXNlID0gb2JqZWN0QExSJExSc2lnLCBrZXkgPSAicGF0aHdheV9uYW1lIiwgbWF0Y2hpbmcuZXhhY3QgPSBULCBwYWlyLm9ubHkgPSBUKQogICAgICBwYWlyTFIudXNlIDwtIHJiaW5kKHBhaXJMUi51c2UsIHBhaXJMUi51c2UuaSkKICAgIH0KICB9CgogIGlmICghaXMubnVsbChwYWlyTFIudXNlKSl7CiAgICBpZiAoImludGVyYWN0aW9uX25hbWUiICVpbiUgY29sbmFtZXMocGFpckxSLnVzZSkpIHsKICAgICAgbmV0IDwtIHN1YnNldChuZXQsaW50ZXJhY3Rpb25fbmFtZSAlaW4lIHBhaXJMUi51c2UkaW50ZXJhY3Rpb25fbmFtZSkKICAgIH0gZWxzZSBpZiAoInBhdGh3YXlfbmFtZSIgJWluJSBjb2xuYW1lcyhwYWlyTFIudXNlKSkgewogICAgICBuZXQgPC0gc3Vic2V0KG5ldCwgcGF0aHdheV9uYW1lICVpbiUgYXMuY2hhcmFjdGVyKHBhaXJMUi51c2UkcGF0aHdheV9uYW1lKSkKICAgIH0KICB9CgogIGlmIChzbG90Lm5hbWUgPT0gIm5ldFAiKSB7CiAgICBuZXQgPC0gZHBseXI6OnNlbGVjdChuZXQsIGMoInNvdXJjZSIsInRhcmdldCIsInBhdGh3YXlfbmFtZSIsInByb2IiKSkKICAgIG5ldCRzb3VyY2VfdGFyZ2V0IDwtIHBhc3RlKG5ldCRzb3VyY2UsIG5ldCR0YXJnZXQsIHNlcCA9ICJzb3VyY2VUb3RhcmdldCIpCiAgICBuZXQgPC0gbmV0ICU+JSBkcGx5cjo6Z3JvdXBfYnkoc291cmNlX3RhcmdldCwgcGF0aHdheV9uYW1lKSAlPiUgZHBseXI6OnN1bW1hcml6ZShwcm9iID0gc3VtKHByb2IpKQogICAgYSA8LSBzdHJpbmdyOjpzdHJfc3BsaXQobmV0JHNvdXJjZV90YXJnZXQsICJzb3VyY2VUb3RhcmdldCIsIHNpbXBsaWZ5ID0gVCkKICAgIG5ldCRzb3VyY2UgPC0gYXMuY2hhcmFjdGVyKGFbLCAxXSkKICAgIG5ldCR0YXJnZXQgPC0gYXMuY2hhcmFjdGVyKGFbLCAyXSkKICAgIG5ldCRsaWdhbmQgPC0gbmV0JHBhdGh3YXlfbmFtZQogICAgbmV0JHJlY2VwdG9yIDwtICIgIgogIH0KCiAgIyBrZWVwIHRoZSBpbnRlcmFjdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHNvdXJjZXMgYW5kIHRhcmdldHMgb2YgaW50ZXJlc3QKICBpZiAoIWlzLm51bGwoc291cmNlcy51c2UpKXsKICAgIGlmIChpcy5udW1lcmljKHNvdXJjZXMudXNlKSkgewogICAgICBzb3VyY2VzLnVzZSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbc291cmNlcy51c2VdCiAgICB9CiAgICBuZXQgPC0gc3Vic2V0KG5ldCwgc291cmNlICVpbiUgc291cmNlcy51c2UpCiAgfSBlbHNlIHsKICAgIHNvdXJjZXMudXNlIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKQogIH0KICBpZiAoIWlzLm51bGwodGFyZ2V0cy51c2UpKXsKICAgIGlmIChpcy5udW1lcmljKHRhcmdldHMudXNlKSkgewogICAgICB0YXJnZXRzLnVzZSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbdGFyZ2V0cy51c2VdCiAgICB9CiAgICBuZXQgPC0gc3Vic2V0KG5ldCwgdGFyZ2V0ICVpbiUgdGFyZ2V0cy51c2UpCiAgfSBlbHNlIHsKICAgIHRhcmdldHMudXNlIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKQogIH0KICAjIHJlbW92ZSB0aGUgaW50ZXJhY3Rpb25zIHdpdGggemVybyB2YWx1ZXMKICBkZiA8LSBzdWJzZXQobmV0LCBwcm9iID4gMCkKCiAgaWYgKG5yb3coZGYpID09IDApIHsKICAgIHN0b3AoIk5vIHNpZ25hbGluZyBsaW5rcyBhcmUgaW5mZXJyZWQhICIpCiAgfQoKICBpZiAobGVuZ3RoKHVuaXF1ZShuZXQkbGlnYW5kKSkgPT0gMSkgewogICAgbWVzc2FnZSgiWW91IG1heSB0cnkgdGhlIGZ1bmN0aW9uIGBuZXRWaXN1YWxfY2hvcmRfY2VsbGAgZm9yIHZpc3VhbGl6aW5nIGluZGl2aWR1YWwgc2lnbmFsaW5nIHBhdGh3YXkiKQogIH0KCiAgZGYkaWQgPC0gMTpucm93KGRmKQogICMgZGVhbCB3aXRoIGR1cGxpY2F0ZWQgc2VjdG9yIG5hbWVzCiAgbGlnYW5kLnVuaSA8LSB1bmlxdWUoZGYkbGlnYW5kKQogIGZvciAoaSBpbiAxOmxlbmd0aChsaWdhbmQudW5pKSkgewogICAgZGYuaSA8LSBkZltkZiRsaWdhbmQgPT0gbGlnYW5kLnVuaVtpXSwgXQogICAgc291cmNlLnVuaSA8LSB1bmlxdWUoZGYuaSRzb3VyY2UpCiAgICBmb3IgKGogaW4gMTpsZW5ndGgoc291cmNlLnVuaSkpIHsKICAgICAgZGYuaS5qIDwtIGRmLmlbZGYuaSRzb3VyY2UgPT0gc291cmNlLnVuaVtqXSwgXQogICAgICBkZi5pLmokbGlnYW5kIDwtIHBhc3RlMChkZi5pLmokbGlnYW5kLCBwYXN0ZShyZXAoJyAnLGotMSksY29sbGFwc2UgPSAnJykpCiAgICAgIGRmJGxpZ2FuZFtkZiRpZCAlaW4lIGRmLmkuaiRpZF0gPC0gZGYuaS5qJGxpZ2FuZAogICAgfQogIH0KICByZWNlcHRvci51bmkgPC0gdW5pcXVlKGRmJHJlY2VwdG9yKQogIGZvciAoaSBpbiAxOmxlbmd0aChyZWNlcHRvci51bmkpKSB7CiAgICBkZi5pIDwtIGRmW2RmJHJlY2VwdG9yID09IHJlY2VwdG9yLnVuaVtpXSwgXQogICAgdGFyZ2V0LnVuaSA8LSB1bmlxdWUoZGYuaSR0YXJnZXQpCiAgICBmb3IgKGogaW4gMTpsZW5ndGgodGFyZ2V0LnVuaSkpIHsKICAgICAgZGYuaS5qIDwtIGRmLmlbZGYuaSR0YXJnZXQgPT0gdGFyZ2V0LnVuaVtqXSwgXQogICAgICBkZi5pLmokcmVjZXB0b3IgPC0gcGFzdGUwKGRmLmkuaiRyZWNlcHRvciwgcGFzdGUocmVwKCcgJyxqLTEpLGNvbGxhcHNlID0gJycpKQogICAgICBkZiRyZWNlcHRvcltkZiRpZCAlaW4lIGRmLmkuaiRpZF0gPC0gZGYuaS5qJHJlY2VwdG9yCiAgICB9CiAgfQoKICBjZWxsLm9yZGVyLnNvdXJjZXMgPC0gbGV2ZWxzKG9iamVjdEBpZGVudHMpW2xldmVscyhvYmplY3RAaWRlbnRzKSAlaW4lIHNvdXJjZXMudXNlXQogIGNlbGwub3JkZXIudGFyZ2V0cyA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbbGV2ZWxzKG9iamVjdEBpZGVudHMpICVpbiUgdGFyZ2V0cy51c2VdCgogIGRmJHNvdXJjZSA8LSBmYWN0b3IoZGYkc291cmNlLCBsZXZlbHMgPSBjZWxsLm9yZGVyLnNvdXJjZXMpCiAgZGYkdGFyZ2V0IDwtIGZhY3RvcihkZiR0YXJnZXQsIGxldmVscyA9IGNlbGwub3JkZXIudGFyZ2V0cykKICAjIGRmLm9yZGVyZWQuc291cmNlIDwtIGRmW3dpdGgoZGYsIG9yZGVyKHNvdXJjZSwgdGFyZ2V0LCAtcHJvYikpLCBdCiAgIyBkZi5vcmRlcmVkLnRhcmdldCA8LSBkZlt3aXRoKGRmLCBvcmRlcih0YXJnZXQsIHNvdXJjZSwgLXByb2IpKSwgXQogIGRmLm9yZGVyZWQuc291cmNlIDwtIGRmW3dpdGgoZGYsIG9yZGVyKHNvdXJjZSwgLXByb2IpKSwgXQogIGRmLm9yZGVyZWQudGFyZ2V0IDwtIGRmW3dpdGgoZGYsIG9yZGVyKHRhcmdldCwgLXByb2IpKSwgXQoKICBvcmRlci5zb3VyY2UgPC0gdW5pcXVlKGRmLm9yZGVyZWQuc291cmNlWyAsYygnbGlnYW5kJywnc291cmNlJyldKQogIG9yZGVyLnRhcmdldCA8LSB1bmlxdWUoZGYub3JkZXJlZC50YXJnZXRbICxjKCdyZWNlcHRvcicsJ3RhcmdldCcpXSkKCiAgIyBkZWZpbmUgc2VjdG9yIG9yZGVyCiAgb3JkZXIuc2VjdG9yIDwtIGMob3JkZXIuc291cmNlJGxpZ2FuZCwgb3JkZXIudGFyZ2V0JHJlY2VwdG9yKQoKICAjIGRlZmluZSBjZWxsIHR5cGUgY29sb3IKICBpZiAoaXMubnVsbChjb2xvci51c2UpKXsKICAgIGNvbG9yLnVzZSA9IHNjUGFsZXR0ZShubGV2ZWxzKG9iamVjdEBpZGVudHMpKQogICAgbmFtZXMoY29sb3IudXNlKSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cykKICAgIGNvbG9yLnVzZSA8LSBjb2xvci51c2VbbGV2ZWxzKG9iamVjdEBpZGVudHMpICVpbiUgYXMuY2hhcmFjdGVyKHVuaW9uKGRmJHNvdXJjZSxkZiR0YXJnZXQpKV0KICB9IGVsc2UgaWYgKGlzLm51bGwobmFtZXMoY29sb3IudXNlKSkpIHsKICAgIG5hbWVzKGNvbG9yLnVzZSkgPC0gbGV2ZWxzKG9iamVjdEBpZGVudHMpCiAgICBjb2xvci51c2UgPC0gY29sb3IudXNlW2xldmVscyhvYmplY3RAaWRlbnRzKSAlaW4lIGFzLmNoYXJhY3Rlcih1bmlvbihkZiRzb3VyY2UsZGYkdGFyZ2V0KSldCiAgfQoKICAjIGRlZmluZSBlZGdlIGNvbG9yCiAgZWRnZS5jb2xvciA8LSBjb2xvci51c2VbYXMuY2hhcmFjdGVyKGRmLm9yZGVyZWQuc291cmNlJHNvdXJjZSldCiAgbmFtZXMoZWRnZS5jb2xvcikgPC0gYXMuY2hhcmFjdGVyKGRmLm9yZGVyZWQuc291cmNlJHNvdXJjZSkKCiAgIyBkZWZpbmUgZ3JpZCBjb2xvcnMKICBncmlkLmNvbC5saWdhbmQgPC0gY29sb3IudXNlW2FzLmNoYXJhY3RlcihvcmRlci5zb3VyY2Ukc291cmNlKV0KICBuYW1lcyhncmlkLmNvbC5saWdhbmQpIDwtIGFzLmNoYXJhY3RlcihvcmRlci5zb3VyY2Ukc291cmNlKQogIGdyaWQuY29sLnJlY2VwdG9yIDwtIGNvbG9yLnVzZVthcy5jaGFyYWN0ZXIob3JkZXIudGFyZ2V0JHRhcmdldCldCiAgbmFtZXMoZ3JpZC5jb2wucmVjZXB0b3IpIDwtIGFzLmNoYXJhY3RlcihvcmRlci50YXJnZXQkdGFyZ2V0KQogIGdyaWQuY29sIDwtIGMoYXMuY2hhcmFjdGVyKGdyaWQuY29sLmxpZ2FuZCksIGFzLmNoYXJhY3RlcihncmlkLmNvbC5yZWNlcHRvcikpCiAgbmFtZXMoZ3JpZC5jb2wpIDwtIG9yZGVyLnNlY3RvcgoKICBkZi5wbG90IDwtIGRmLm9yZGVyZWQuc291cmNlWyAsYygnbGlnYW5kJywncmVjZXB0b3InLCdwcm9iJyldCgogIGlmIChkaXJlY3Rpb25hbCA9PSAyKSB7CiAgICBsaW5rLmFyci50eXBlID0gInRyaWFuZ2xlIgogIH0gZWxzZSB7CiAgICBsaW5rLmFyci50eXBlID0gImJpZy5hcnJvdyIKICB9CiAgY2lyY29zLmNsZWFyKCkKICBjaG9yZERpYWdyYW0oZGYucGxvdCwKICAgICAgICAgICAgICAgb3JkZXIgPSBvcmRlci5zZWN0b3IsCiAgICAgICAgICAgICAgIGNvbCA9IGVkZ2UuY29sb3IsCiAgICAgICAgICAgICAgIGdyaWQuY29sID0gZ3JpZC5jb2wsCiAgICAgICAgICAgICAgIHRyYW5zcGFyZW5jeSA9IHRyYW5zcGFyZW5jeSwKICAgICAgICAgICAgICAgbGluay5ib3JkZXIgPSBsaW5rLmJvcmRlciwKICAgICAgICAgICAgICAgZGlyZWN0aW9uYWwgPSBkaXJlY3Rpb25hbCwKICAgICAgICAgICAgICAgZGlyZWN0aW9uLnR5cGUgPSBjKCJkaWZmSGVpZ2h0IiwiYXJyb3dzIiksCiAgICAgICAgICAgICAgIGxpbmsuYXJyLnR5cGUgPSBsaW5rLmFyci50eXBlLAogICAgICAgICAgICAgICBhbm5vdGF0aW9uVHJhY2sgPSAiZ3JpZCIsCiAgICAgICAgICAgICAgIGFubm90YXRpb25UcmFja0hlaWdodCA9IGFubm90YXRpb25UcmFja0hlaWdodCwKICAgICAgICAgICAgICAgcHJlQWxsb2NhdGVUcmFja3MgPSBsaXN0KHRyYWNrLmhlaWdodCA9IG1heChzdHJ3aWR0aChvcmRlci5zZWN0b3IpKSksCiAgICAgICAgICAgICAgIHNtYWxsLmdhcCA9IHNtYWxsLmdhcCwKICAgICAgICAgICAgICAgYmlnLmdhcCA9IGJpZy5nYXAsCiAgICAgICAgICAgICAgIGxpbmsudmlzaWJsZSA9IGxpbmsudmlzaWJsZSwKICAgICAgICAgICAgICAgc2NhbGUgPSBzY2FsZSwKICAgICAgICAgICAgICAgbGluay50YXJnZXQucHJvcCA9IGxpbmsudGFyZ2V0LnByb3AsCiAgICAgICAgICAgICAgIHJlZHVjZSA9IHJlZHVjZSwKICAgICAgICAgICAgICAgLi4uKQoKICBjaXJjb3MudHJhY2sodHJhY2suaW5kZXggPSAxLCBwYW5lbC5mdW4gPSBmdW5jdGlvbih4LCB5KSB7CiAgICB4bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4bGltIikKICAgIHhwbG90ID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4cGxvdCIpCiAgICB5bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ5bGltIikKICAgIHNlY3Rvci5uYW1lID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJzZWN0b3IuaW5kZXgiKQogICAgY2lyY29zLnRleHQobWVhbih4bGltKSwgeWxpbVsxXSwgc2VjdG9yLm5hbWUsZmFjaW5nID0gImNsb2Nrd2lzZSIsIG5pY2VGYWNpbmcgPSBUUlVFLCBhZGo9YygwLjUsMC4wMSksY2V4ID0gbGFiLmNleCkKICB9LCBiZy5ib3JkZXIgPSBOQSkKCgogICMgaHR0cHM6Ly9qb2tlcmdvby5naXRodWIuaW8vY2lyY2xpemVfYm9vay9ib29rL2xlZ2VuZHMuaHRtbAogIGlmIChzaG93LmxlZ2VuZCkgewogICAgbGdkIDwtIENvbXBsZXhIZWF0bWFwOjpMZWdlbmQoYXQgPSBuYW1lcyhjb2xvci51c2UpLCB0eXBlID0gImdyaWQiLCBsZWdlbmRfZ3AgPSBncmlkOjpncGFyKGZpbGwgPSBjb2xvci51c2UpLCB0aXRsZSA9ICJDZWxsIFN0YXRlIikKICAgIENvbXBsZXhIZWF0bWFwOjpkcmF3KGxnZCwgeCA9IHVuaXQoMSwgIm5wYyIpLXVuaXQobGVnZW5kLnBvcy54LCAibW0iKSwgeSA9IHVuaXQobGVnZW5kLnBvcy55LCAibW0iKSwganVzdCA9IGMoInJpZ2h0IiwgImJvdHRvbSIpKQogIH0KCiAgY2lyY29zLmNsZWFyKCkKICBpZighaXMubnVsbCh0aXRsZS5uYW1lKSl7CiAgICB0ZXh0KC0wLCAxLjAyLCB0aXRsZS5uYW1lLCBjZXg9MSkKICB9CiAgZ2cgPC0gcmVjb3JkUGxvdCgpCiAgcmV0dXJuKGdnKQp9CmBgYAoKYGBge3IgZmlnLmhlaWdodD0xNSxmaWcud2lkdGg9MTV9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJDWENMIiksIGxlZ2VuZC5wb3MueCA9IDgsIHNjYWxlPUZBTFNFLHNvdXJjZXMudXNlID0gYyg1Nyw2MyksIGxhYi5jZXg9MC41LGNvbG9yLnVzZSA9IGNvbG91cnMpIApgYGAKYGBge3IgZmlnLmhlaWdodD0xNSxmaWcud2lkdGg9MTV9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJDWENMIiksIGxlZ2VuZC5wb3MueCA9IDgsIHNjYWxlPVRSVUUsc291cmNlcy51c2UgPSBjKDU3LDYzKSx0YXJnZXRzLnVzZSA9YygyNCwyOSw0Niw1MCw2MCw2Miw2OSw3MCw3Miw3MyksIGxhYi5jZXg9MC41LGNvbG9yLnVzZSA9IGNvbG91cnMpIApgYGAKYGBge3IgZmlnLmhlaWdodD0xNSxmaWcud2lkdGg9MTV9CnBkZihmaWxlID0iYWxsX2dlbmVzX3Bsb3RzL2NlbGxjaGF0X01VQzZPcmFsRmlicm9zb3VyY2VfY3hjbGNob3JkLnBkZiIsIHdpZHRoID0gMTUsIGhlaWdodCA9MTUpCm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJDWENMIiksIGxlZ2VuZC5wb3MueCA9IDgsIHNjYWxlPVRSVUUsc291cmNlcy51c2UgPSBjKDU3LDYzKSx0YXJnZXRzLnVzZSA9YygyNCwyOSw0Niw1MCw2MCw2Miw2OSw3MCw3Miw3MyksIGxhYi5jZXg9MC41LGNvbG9yLnVzZSA9IGNvbG91cnMpIApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTUsZmlnLndpZHRoPTE1fQpuZXRWaXN1YWxfY2hvcmRfZ2VuZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gYygiQ1hDTCIpLCBsZWdlbmQucG9zLnggPSA4LCBzY2FsZT1UUlVFLHNvdXJjZXMudXNlID0gYyg1NyksIGxhYi5jZXg9MSxjb2xvci51c2UgPSBjb2xvdXJzKSAKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xNSxmaWcud2lkdGg9MTV9CnBkZihmaWxlID0iYWxsX2dlbmVzX3Bsb3RzL2NlbGxjaGF0X01VQzZzb3VyY2VfY3hjbGNob3JkLnBkZiIsIHdpZHRoID0gMTUsIGhlaWdodCA9MTUpCm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJDWENMIiksIGxlZ2VuZC5wb3MueCA9IDgsIHNjYWxlPVRSVUUsc291cmNlcy51c2UgPSBjKDU3KSwgbGFiLmNleD0xLGNvbG9yLnVzZSA9IGNvbG91cnMpIApgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTE1LGZpZy53aWR0aD0xNX0KbmV0VmlzdWFsX2Nob3JkX2dlbmUoY2VsbGNoYXQsIHNpZ25hbGluZyA9IGMoIkNDTCIpLCBsZWdlbmQucG9zLnggPSA4LCBzY2FsZT1GQUxTRSxzb3VyY2VzLnVzZSA9IGMoNTcsNjMpLCBsYWIuY2V4PTAuNSxjb2xvci51c2UgPSBjb2xvdXJzKSAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTE1LGZpZy53aWR0aD0xNX0KbmV0VmlzdWFsX2Nob3JkX2dlbmUoY2VsbGNoYXQsIHNpZ25hbGluZyA9IGMoIkNYQ0wiKSwgbGVnZW5kLnBvcy54ID0gOCwgc2NhbGU9RkFMU0Usc291cmNlcy51c2UgPSBjKDU3LDYzKSwgbGFiLmNleD0wLjUsY29sb3IudXNlID0gY29sb3VycykgCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9MTUsZmlnLndpZHRoPTE1fQpuZXRWaXN1YWxfY2hvcmRfZ2VuZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gYygiTUhDLUlJIiksIGxlZ2VuZC5wb3MueCA9IDgsIHNjYWxlPUZBTFNFLHNvdXJjZXMudXNlID0gYyg1NyksIGxhYi5jZXg9MC41LGNvbG9yLnVzZSA9IGNvbG91cnMpIApgYGAKCgojIyMgY29kZSBmcm9tIHByZXZpb3VzIG5vdGVib29rCmBgYHtyIGZpZy5oZWlnaHQ9MTUsZmlnLndpZHRoPTE1fQpuZXRWaXN1YWxfY2hvcmRfZ2VuZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gYygiSUw2IiksbGVnZW5kLnBvcy54ID0gOCwgc2NhbGU9RkFMU0UsIHNvdXJjZXMudXNlID0gYygxLDIsMyw0LDUsNiw3KSwgdGFyZ2V0cy51c2UgPSBjKDEsMiwzLDQsNSw2LDcpLCBsYWIuY2V4PTEsICBjb2xvci51c2UgPSBjKCcjQ0Q2NjAwJywgJyNGRjhDMDAnLCAnI0NEMDBDRCcsJyMwMDAwRUUnLCAnIzhGQkM4RicsJyNDMUZGQzEnLCcjMjI4QjIyJykpIApgYGAKCmBgYHtyfQpuZXRWaXN1YWxfY2hvcmRfZ2VuZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gYygiQ0NMIiksbGVnZW5kLnBvcy54ID0gOCwgc2NhbGU9VFJVRSwgc291cmNlcy51c2UgPSBjKDUsNiw3KSwgdGFyZ2V0cy51c2UgPSBjKDEsMiwzLDQsNSw2LDcpLCBsYWIuY2V4PTAuNSwgIGNvbG9yLnVzZSA9IGMoJyNDRDY2MDAnLCAnI0ZGOEMwMCcsICcjQ0QwMENEJywgJyMwMDAwRUUnLCAgJyM4RkJDOEYnLCcjQzFGRkMxJywnIzIyOEIyMicpKSAKCmBgYAoKYGBge3J9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJJTDYiKSxsZWdlbmQucG9zLnggPSA4LCBzY2FsZT1UUlVFLCBzb3VyY2VzLnVzZSA9IGMoNSw2LDcpLCB0YXJnZXRzLnVzZSA9IGMoMSwyLDMsNCksIGxhYi5jZXg9MS41LCBjb2xvci51c2UgPSBjKCcjQ0Q2NjAwJywgJyNGRjhDMDAnLCAnI0NEMDBDRCcsICAnIzQxNjlFMScsICcjMDAwMEVFJywgJyNBREQ4RTYnLCAnIzhGQkM4RicsJyNDMUZGQzEnLCcjMjI4QjIyJywnIzY0OTVFRCcpKSAKCmBgYAoKYGBge3J9Cm5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0LCBzaWduYWxpbmcgPSBjKCJJTDYiKSxsZWdlbmQucG9zLnggPSA4LCBzY2FsZT1UUlVFLCBsYWIuY2V4PTEsICBjb2xvci51c2UgPSBjKCcjQ0Q2NjAwJywgJyNGRjhDMDAnLCAnI0NEMDBDRCcsJyMwMDAwRUUnLCAnIzhGQkM4RicsJyNDMUZGQzEnLCcjMjI4QjIyJykpCmBgYAoKQmVsb3cgaXMganVzdCBjaGFuZ2VzIHRvIHRoZSBkZWZhdWx0IGNpcmNsZS9jaG9yZCBwbG90cyBmcm9tIHRoZSBzb3VyY2UgY29kZSwgdGhlIGRlZmF1bHQgb3B0aW9uIGlzIHRvIGhhdmUgdGhlIGxhYmVscyBzdGlja2luZyBvdXQgZnJvbSB0aGUgcGxvdCBpbnN0ZWFkIG9mIHdyYXBwaW5nIGFyb3VuZCB0aGlzIGNhbiBiZSBjaGFuZ2VkIGluIGNpcmNvcy50ZXh0IHNldHRpbmcgZmFjaW5nIChodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvY2lyY2xpemUvdmVyc2lvbnMvMC40LjEzL3RvcGljcy9jaXJjb3MudGV4dCkKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsZmlnLndpZHRoPTEwfQojSExBLURSQQpwYXRod2F5cy5zaG93IDwtIGMoIk1IQy1JSSIpCnBhaXJMUi5NSENJSSA8LSBleHRyYWN0RW5yaWNoZWRMUihjZWxsY2hhdCwgc2lnbmFsaW5nID0gcGF0aHdheXMuc2hvdywgZ2VuZUxSLnJldHVybiA9IEZBTFNFKQpMUi5zaG93IDwtIHBhaXJMUi5NSENJSVsxMSxdICNITEEtRFJBIGlzIDEwIGFuZCBITEEtRFJCMSBpcyAxMQpuZXRWaXN1YWxfaW5kaXZpZHVhbChjZWxsY2hhdCwgc2lnbmFsaW5nID0gcGF0aHdheXMuc2hvdywgcGFpckxSLnVzZSA9IExSLnNob3csIGxheW91dCA9ICJjaG9yZCIsIGNvbG9yLnVzZSA9IGMoJyNDRDY2MDAnLCAnI0ZGOEMwMCcsICcjQ0QwMENEJywgICcjNDE2OUUxJywgJyMwMDAwRUUnLCAnI0FERDhFNicsICcjOEZCQzhGJywnI0MxRkZDMScsJyMyMjhCMjInLCcjNjQ5NUVEJykscmVtb3ZlLmlzb2xhdGU9VFJVRSkKYGBgCmBgYHtyfQpuZXRWaXN1YWxfaW5kaXZpZHVhbCA8LSBmdW5jdGlvbihvYmplY3QsIHNpZ25hbGluZywgc2lnbmFsaW5nLm5hbWUgPSBOVUxMLCBwYWlyTFIudXNlID0gTlVMTCwgY29sb3IudXNlID0gTlVMTCwgdmVydGV4LnJlY2VpdmVyID0gTlVMTCwgc291cmNlcy51c2UgPSBOVUxMLCB0YXJnZXRzLnVzZSA9IE5VTEwsIHRvcCA9IDEsIHJlbW92ZS5pc29sYXRlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRleC53ZWlnaHQgPSAxLCB2ZXJ0ZXgud2VpZ2h0Lm1heCA9IE5VTEwsIHZlcnRleC5zaXplLm1heCA9IE5VTEwsIHZlcnRleC5sYWJlbC5jZXggPSAwLjgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodC5zY2FsZSA9IEZBTFNFLCBlZGdlLndlaWdodC5tYXggPSBOVUxMLCBlZGdlLndpZHRoLm1heD04LCBncmFwaGljcy5pbml0ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0ID0gYygiY2lyY2xlIiwiaGllcmFyY2h5IiwiY2hvcmQiKSwgaGVpZ2h0ID0gNSwgdGhyZXNoID0gMC4wNSwgI2Zyb20gPSBOVUxMLCB0byA9IE5VTEwsIGJpZGlyZWN0aW9uID0gTlVMTCx2ZXJ0ZXguc2l6ZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gTlVMTCxjZWxsLm9yZGVyID0gTlVMTCxzbWFsbC5nYXAgPSAxLCBiaWcuZ2FwID0gMTAsIHNjYWxlID0gRkFMU0UsIHJlZHVjZSA9IC0xLCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBsZWdlbmQucG9zLnggPSAyMCwgbGVnZW5kLnBvcy55ID0gMjAsIG5Db2wgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4pIHsKICBsYXlvdXQgPC0gbWF0Y2guYXJnKGxheW91dCkKICAjIGlmICghaXMubnVsbCh2ZXJ0ZXguc2l6ZSkpIHsKICAjICAgd2FybmluZygiJ3ZlcnRleC5zaXplJyBpcyBkZXByZWNhdGVkLiBVc2UgYHZlcnRleC53ZWlnaHRgIikKICAjIH0KICBpZiAoaXMubnVsbCh2ZXJ0ZXgud2VpZ2h0KSkgewogICAgdmVydGV4LndlaWdodCA8LSBhcy5udW1lcmljKHRhYmxlKG9iamVjdEBpZGVudHMpKQogIH0KICBpZiAoaXMubnVsbCh2ZXJ0ZXguc2l6ZS5tYXgpKSB7CiAgICBpZiAobGVuZ3RoKHVuaXF1ZSh2ZXJ0ZXgud2VpZ2h0KSkgPT0gMSkgewogICAgICB2ZXJ0ZXguc2l6ZS5tYXggPC0gNQogICAgfSBlbHNlIHsKICAgICAgdmVydGV4LnNpemUubWF4IDwtIDE1CiAgICB9CiAgfQoKICBwYWlyTFIgPC0gc2VhcmNoUGFpcihzaWduYWxpbmcgPSBzaWduYWxpbmcsIHBhaXJMUi51c2UgPSBvYmplY3RATFIkTFJzaWcsIGtleSA9ICJwYXRod2F5X25hbWUiLCBtYXRjaGluZy5leGFjdCA9IFQsIHBhaXIub25seSA9IEYpCgogIGlmIChpcy5udWxsKHNpZ25hbGluZy5uYW1lKSkgewogICAgc2lnbmFsaW5nLm5hbWUgPC0gc2lnbmFsaW5nCiAgfQogIG5ldCA8LSBvYmplY3RAbmV0CgogIHBhaXJMUi51c2UubmFtZSA8LSBkaW1uYW1lcyhuZXQkcHJvYilbWzNdXQogIHBhaXJMUi5uYW1lIDwtIGludGVyc2VjdChyb3duYW1lcyhwYWlyTFIpLCBwYWlyTFIudXNlLm5hbWUpCiAgaWYgKCFpcy5udWxsKHBhaXJMUi51c2UpKSB7CiAgICBpZiAoaXMuZGF0YS5mcmFtZShwYWlyTFIudXNlKSkgewogICAgICBwYWlyTFIubmFtZSA8LSBpbnRlcnNlY3QocGFpckxSLm5hbWUsIGFzLmNoYXJhY3RlcihwYWlyTFIudXNlJGludGVyYWN0aW9uX25hbWUpKQogICAgfSBlbHNlIHsKICAgICAgcGFpckxSLm5hbWUgPC0gaW50ZXJzZWN0KHBhaXJMUi5uYW1lLCBhcy5jaGFyYWN0ZXIocGFpckxSLnVzZSkpCiAgICB9CgogICAgaWYgKGxlbmd0aChwYWlyTFIubmFtZSkgPT0gMCkgewogICAgICBzdG9wKCJUaGVyZSBpcyBubyBzaWduaWZpY2FudCBjb21tdW5pY2F0aW9uIGZvciB0aGUgaW5wdXQgTC1SIHBhaXJzISIpCiAgICB9CiAgfQoKICBwYWlyTFIgPC0gcGFpckxSW3BhaXJMUi5uYW1lLCBdCiAgcHJvYiA8LSBuZXQkcHJvYgogIHB2YWwgPC0gbmV0JHB2YWwKCiAgcHJvYltwdmFsID4gdGhyZXNoXSA8LSAwCiAgaWYgKGxlbmd0aChwYWlyTFIubmFtZSkgPiAxKSB7CiAgICBwYWlyTFIubmFtZS51c2UgPC0gcGFpckxSLm5hbWVbYXBwbHkocHJvYlssLHBhaXJMUi5uYW1lXSwgMywgc3VtKSAhPSAwXQogIH0gZWxzZSB7CiAgICBwYWlyTFIubmFtZS51c2UgPC0gcGFpckxSLm5hbWVbc3VtKHByb2JbLCxwYWlyTFIubmFtZV0pICE9IDBdCiAgfQoKICBpZiAobGVuZ3RoKHBhaXJMUi5uYW1lLnVzZSkgPT0gMCkgewogICAgc3RvcChwYXN0ZTAoJ1RoZXJlIGlzIG5vIHNpZ25pZmljYW50IGNvbW11bmljYXRpb24gb2YgJywgc2lnbmFsaW5nLm5hbWUpKQogIH0gZWxzZSB7CiAgICBwYWlyTFIgPC0gcGFpckxSW3BhaXJMUi5uYW1lLnVzZSxdCiAgfQoKICBuUm93IDwtIGxlbmd0aChwYWlyTFIubmFtZS51c2UpCgogIHByb2IgPC0gcHJvYlssLHBhaXJMUi5uYW1lLnVzZV0KICBwdmFsIDwtIHB2YWxbLCxwYWlyTFIubmFtZS51c2VdCgogIGlmIChpcy5udWxsKG5Db2wpKSB7CiAgICBuQ29sIDwtIG1pbihsZW5ndGgocGFpckxSLm5hbWUudXNlKSwgMikKICB9CgogIGlmIChsZW5ndGgoZGltKHByb2IpKSA9PSAyKSB7CiAgICBwcm9iIDwtIHJlcGxpY2F0ZSgxLCBwcm9iLCBzaW1wbGlmeT0iYXJyYXkiKQogICAgcHZhbCA8LSByZXBsaWNhdGUoMSwgcHZhbCwgc2ltcGxpZnk9ImFycmF5IikKICB9CgogIyBwcm9iIDwtKHByb2ItbWluKHByb2IpKS8obWF4KHByb2IpLW1pbihwcm9iKSkKICBpZiAoaXMubnVsbChlZGdlLndlaWdodC5tYXgpKSB7CiAgICBlZGdlLndlaWdodC5tYXggPSBtYXgocHJvYikKICB9CgogIGlmIChsYXlvdXQgPT0gImhpZXJhcmNoeSIpIHsKICAgIGlmIChncmFwaGljcy5pbml0KSB7CiAgICAgIHBhcihtZnJvdz1jKG5Sb3csMiksIG1hciA9IGMoNSwgNCwgNCwgMikgKzAuMSkKICAgIH0KCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgocGFpckxSLm5hbWUudXNlKSkgewogICAgICBzaWduYWxOYW1lX2kgPC0gcGFpckxSJGludGVyYWN0aW9uX25hbWVfMltpXQogICAgICBwcm9iLmkgPC0gcHJvYlssLGldCiAgICAgIG5ldFZpc3VhbF9oaWVyYXJjaHkxKHByb2IuaSwgdmVydGV4LnJlY2VpdmVyID0gdmVydGV4LnJlY2VpdmVyLCBzb3VyY2VzLnVzZSA9IHNvdXJjZXMudXNlLCB0YXJnZXRzLnVzZSA9IHRhcmdldHMudXNlLCByZW1vdmUuaXNvbGF0ZSA9IHJlbW92ZS5pc29sYXRlLCB0b3AgPSB0b3AsIGNvbG9yLnVzZSA9IGNvbG9yLnVzZSwgdmVydGV4LndlaWdodCA9IHZlcnRleC53ZWlnaHQsIHZlcnRleC53ZWlnaHQubWF4ID0gdmVydGV4LndlaWdodC5tYXgsIHZlcnRleC5zaXplLm1heCA9IHZlcnRleC5zaXplLm1heCwgd2VpZ2h0LnNjYWxlID0gd2VpZ2h0LnNjYWxlLCBlZGdlLndlaWdodC5tYXggPSBlZGdlLndlaWdodC5tYXgsIGVkZ2Uud2lkdGgubWF4PWVkZ2Uud2lkdGgubWF4LCB0aXRsZS5uYW1lID0gc2lnbmFsTmFtZV9pLC4uLikKICAgICAgbmV0VmlzdWFsX2hpZXJhcmNoeTIocHJvYi5pLCB2ZXJ0ZXgucmVjZWl2ZXIgPSBzZXRkaWZmKDE6bnJvdyhwcm9iLmkpLHZlcnRleC5yZWNlaXZlciksIHNvdXJjZXMudXNlID0gc291cmNlcy51c2UsIHRhcmdldHMudXNlID0gdGFyZ2V0cy51c2UsIHJlbW92ZS5pc29sYXRlID0gcmVtb3ZlLmlzb2xhdGUsIHRvcCA9IHRvcCwgY29sb3IudXNlID0gY29sb3IudXNlLCB2ZXJ0ZXgud2VpZ2h0ID0gdmVydGV4LndlaWdodCwgdmVydGV4LndlaWdodC5tYXggPSB2ZXJ0ZXgud2VpZ2h0Lm1heCwgdmVydGV4LnNpemUubWF4ID0gdmVydGV4LnNpemUubWF4LCB3ZWlnaHQuc2NhbGUgPSB3ZWlnaHQuc2NhbGUsIGVkZ2Uud2VpZ2h0Lm1heCA9IGVkZ2Uud2VpZ2h0Lm1heCwgZWRnZS53aWR0aC5tYXg9ZWRnZS53aWR0aC5tYXgsIHRpdGxlLm5hbWUgPSBzaWduYWxOYW1lX2ksLi4uKQogICAgfQogICAgIyBncmlkLmVjaG8oKQogICAgIyBnZyA8LSAgZ3JpZC5ncmFiKCkKICAgIGdnIDwtIHJlY29yZFBsb3QoKQoKICB9IGVsc2UgaWYgKGxheW91dCA9PSAiY2lyY2xlIikgewogICAjIHBhcihtZnJvdz1jKG5Sb3csMSkpCiAgICBpZiAoZ3JhcGhpY3MuaW5pdCkgewogICAgICBwYXIobWZyb3cgPSBjKGNlaWxpbmcobGVuZ3RoKHBhaXJMUi5uYW1lLnVzZSkvbkNvbCksIG5Db2wpLCB4cGQ9VFJVRSkKICAgIH0KCiAgICBnZyA8LSB2ZWN0b3IoImxpc3QiLCBsZW5ndGgocGFpckxSLm5hbWUudXNlKSkKICAgIGZvciAoaSBpbiAxOmxlbmd0aChwYWlyTFIubmFtZS51c2UpKSB7CiAgICAgIHNpZ25hbE5hbWVfaSA8LSBwYWlyTFIkaW50ZXJhY3Rpb25fbmFtZV8yW2ldCiAgICAgIHByb2IuaSA8LSBwcm9iWywsaV0KICAgICAgZ2dbW2ldXSA8LSBuZXRWaXN1YWxfY2lyY2xlKHByb2IuaSwgc291cmNlcy51c2UgPSBzb3VyY2VzLnVzZSwgdGFyZ2V0cy51c2UgPSB0YXJnZXRzLnVzZSwgcmVtb3ZlLmlzb2xhdGUgPSByZW1vdmUuaXNvbGF0ZSwgdG9wID0gdG9wLCBjb2xvci51c2UgPSBjb2xvci51c2UsIHZlcnRleC53ZWlnaHQgPSB2ZXJ0ZXgud2VpZ2h0LCB2ZXJ0ZXgud2VpZ2h0Lm1heCA9IHZlcnRleC53ZWlnaHQubWF4LCB2ZXJ0ZXguc2l6ZS5tYXggPSB2ZXJ0ZXguc2l6ZS5tYXgsIHdlaWdodC5zY2FsZSA9IHdlaWdodC5zY2FsZSwgZWRnZS53ZWlnaHQubWF4ID0gZWRnZS53ZWlnaHQubWF4LCBlZGdlLndpZHRoLm1heD1lZGdlLndpZHRoLm1heCwgdGl0bGUubmFtZSA9IHNpZ25hbE5hbWVfaSwuLi4pCiAgICB9CiAgfSBlbHNlIGlmIChsYXlvdXQgPT0gImNob3JkIikgewogICAgaWYgKGdyYXBoaWNzLmluaXQpIHsKICAgICAgcGFyKG1mcm93ID0gYyhjZWlsaW5nKGxlbmd0aChwYWlyTFIubmFtZS51c2UpL25Db2wpLCBuQ29sKSwgeHBkPVRSVUUpCiAgICB9CgogICAgZ2cgPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoKHBhaXJMUi5uYW1lLnVzZSkpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgocGFpckxSLm5hbWUudXNlKSkgewogICAgICB0aXRsZS5uYW1lIDwtIHBhaXJMUiRpbnRlcmFjdGlvbl9uYW1lXzJbaV0KICAgICAgbmV0IDwtIHByb2JbLCxpXQogICAgICBnZ1tbaV1dIDwtIG5ldFZpc3VhbF9jaG9yZF9jZWxsX2ludGVybmFsKG5ldCwgY29sb3IudXNlID0gY29sb3IudXNlLCBzb3VyY2VzLnVzZSA9IHNvdXJjZXMudXNlLCB0YXJnZXRzLnVzZSA9IHRhcmdldHMudXNlLCByZW1vdmUuaXNvbGF0ZSA9IHJlbW92ZS5pc29sYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZ3JvdXAsIGNlbGwub3JkZXIgPSBjZWxsLm9yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi5jZXggPSB2ZXJ0ZXgubGFiZWwuY2V4LHNtYWxsLmdhcCA9IHNtYWxsLmdhcCwgYmlnLmdhcCA9IGJpZy5nYXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSBzY2FsZSwgcmVkdWNlID0gcmVkdWNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLm5hbWUgPSB0aXRsZS5uYW1lLCBzaG93LmxlZ2VuZCA9IHNob3cubGVnZW5kLCBsZWdlbmQucG9zLnggPSBsZWdlbmQucG9zLngsIGxlZ2VuZC5wb3MueSA9IGxlZ2VuZC5wb3MueSkKICAgIH0KICB9CiAgcmV0dXJuKGdnKQp9CmBgYAoKYGBge3J9Cm5ldFZpc3VhbF9jaG9yZF9jZWxsX2ludGVybmFsIDwtIGZ1bmN0aW9uKG5ldCwgY29sb3IudXNlID0gTlVMTCwgZ3JvdXAgPSBOVUxMLCBjZWxsLm9yZGVyID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlcy51c2UgPSBOVUxMLCB0YXJnZXRzLnVzZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi5jZXggPSAwLjgsc21hbGwuZ2FwID0gMSwgYmlnLmdhcCA9IDEwLCBhbm5vdGF0aW9uVHJhY2tIZWlnaHQgPSBjKDAuMDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdmUuaXNvbGF0ZSA9IEZBTFNFLCBsaW5rLnZpc2libGUgPSBUUlVFLCBzY2FsZSA9IEZBTFNFLCBkaXJlY3Rpb25hbCA9IDEsIGxpbmsudGFyZ2V0LnByb3AgPSBUUlVFLCByZWR1Y2UgPSAtMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNwYXJlbmN5ID0gMC40LCBsaW5rLmJvcmRlciA9IE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZS5uYW1lID0gTlVMTCwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgbGVnZW5kLnBvcy54ID0gMjAsIGxlZ2VuZC5wb3MueSA9IDIwLC4uLil7CiAgaWYgKGluaGVyaXRzKHggPSBuZXQsIHdoYXQgPSBjKCJtYXRyaXgiLCAiTWF0cml4IikpKSB7CiAgICBjZWxsLmxldmVscyA8LSB1bmlvbihyb3duYW1lcyhuZXQpLCBjb2xuYW1lcyhuZXQpKQogICAgbmV0IDwtIHJlc2hhcGUyOjptZWx0KG5ldCwgdmFsdWUubmFtZSA9ICJwcm9iIikKICAgIGNvbG5hbWVzKG5ldClbMToyXSA8LSBjKCJzb3VyY2UiLCJ0YXJnZXQiKQogIH0gZWxzZSBpZiAoaXMuZGF0YS5mcmFtZShuZXQpKSB7CiAgICBpZiAoYWxsKGMoInNvdXJjZSIsInRhcmdldCIsICJwcm9iIikgJWluJSBjb2xuYW1lcyhuZXQpKSA9PSBGQUxTRSkgewogICAgICBzdG9wKCJUaGUgaW5wdXQgZGF0YSBmcmFtZSBtdXN0IGNvbnRhaW4gdGhyZWUgY29sdW1ucyBuYW1lZCBhcyBzb3VyY2UsIHRhcmdldCwgcHJvYiIpCiAgICB9CiAgICBjZWxsLmxldmVscyA8LSBhcy5jaGFyYWN0ZXIodW5pb24obmV0JHNvdXJjZSxuZXQkdGFyZ2V0KSkKICB9CiAgaWYgKCFpcy5udWxsKGNlbGwub3JkZXIpKSB7CiAgICBjZWxsLmxldmVscyA8LSBjZWxsLm9yZGVyCiAgfQogIG5ldCRzb3VyY2UgPC0gYXMuY2hhcmFjdGVyKG5ldCRzb3VyY2UpCiAgbmV0JHRhcmdldCA8LSBhcy5jaGFyYWN0ZXIobmV0JHRhcmdldCkKCiAgIyBrZWVwIHRoZSBpbnRlcmFjdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHNvdXJjZXMgYW5kIHRhcmdldHMgb2YgaW50ZXJlc3QKICBpZiAoIWlzLm51bGwoc291cmNlcy51c2UpKXsKICAgIGlmIChpcy5udW1lcmljKHNvdXJjZXMudXNlKSkgewogICAgICBzb3VyY2VzLnVzZSA8LSBjZWxsLmxldmVsc1tzb3VyY2VzLnVzZV0KICAgIH0KICAgIG5ldCA8LSBzdWJzZXQobmV0LCBzb3VyY2UgJWluJSBzb3VyY2VzLnVzZSkKICB9CiAgaWYgKCFpcy5udWxsKHRhcmdldHMudXNlKSl7CiAgICBpZiAoaXMubnVtZXJpYyh0YXJnZXRzLnVzZSkpIHsKICAgICAgdGFyZ2V0cy51c2UgPC0gY2VsbC5sZXZlbHNbdGFyZ2V0cy51c2VdCiAgICB9CiAgICBuZXQgPC0gc3Vic2V0KG5ldCwgdGFyZ2V0ICVpbiUgdGFyZ2V0cy51c2UpCiAgfQogICMgcmVtb3ZlIHRoZSBpbnRlcmFjdGlvbnMgd2l0aCB6ZXJvIHZhbHVlcwogIG5ldCA8LSBzdWJzZXQobmV0LCBwcm9iID4gMCkKICAjIGNyZWF0ZSBhIGZha2UgZGF0YSBpZiBrZWVwaW5nIHRoZSBjZWxsIHR5cGVzIChpLmUuLCBzZWN0b3JzKSB3aXRob3V0IGFueSBpbnRlcmFjdGlvbnMKICBpZiAoIXJlbW92ZS5pc29sYXRlKSB7CiAgICBjZWxscy5yZW1vdmVkIDwtIHNldGRpZmYoY2VsbC5sZXZlbHMsIGFzLmNoYXJhY3Rlcih1bmlvbihuZXQkc291cmNlLG5ldCR0YXJnZXQpKSkKICAgIGlmIChsZW5ndGgoY2VsbHMucmVtb3ZlZCkgPiAwKSB7CiAgICAgIG5ldC5mYWtlIDwtIGRhdGEuZnJhbWUoY2VsbHMucmVtb3ZlZCwgY2VsbHMucmVtb3ZlZCwgMWUtMTAqc2FtcGxlKGxlbmd0aChjZWxscy5yZW1vdmVkKSwgbGVuZ3RoKGNlbGxzLnJlbW92ZWQpKSkKICAgICAgY29sbmFtZXMobmV0LmZha2UpIDwtIGNvbG5hbWVzKG5ldCkKICAgICAgbmV0IDwtIHJiaW5kKG5ldCwgbmV0LmZha2UpCiAgICAgIGxpbmsudmlzaWJsZSA8LSBuZXRbLCAxOjJdCiAgICAgIGxpbmsudmlzaWJsZSRwbG90IDwtIEZBTFNFCiAgICAgIGxpbmsudmlzaWJsZSRwbG90WzE6KG5yb3cobmV0KSAtIG5yb3cobmV0LmZha2UpKV0gPC0gVFJVRQogICAgICAjIGRpcmVjdGlvbmFsIDwtIG5ldFssIDE6Ml0KICAgICAgIyBkaXJlY3Rpb25hbCRwbG90IDwtIDAKICAgICAgIyBkaXJlY3Rpb25hbCRwbG90WzE6KG5yb3cobmV0KSAtIG5yb3cobmV0LmZha2UpKV0gPC0gMQogICAgICAjIGxpbmsuYXJyLnR5cGUgPSAiYmlnLmFycm93IgogICAgICAjIG1lc3NhZ2UoIlNldCBzY2FsZSA9IFRSVUUgd2hlbiByZW1vdmUuaXNvbGF0ZSA9IEZBTFNFIikKICAgICAgc2NhbGUgPSBUUlVFCiAgICB9CiAgfQoKICBkZiA8LSBuZXQKICBjZWxscy51c2UgPC0gdW5pb24oZGYkc291cmNlLGRmJHRhcmdldCkKCiAgIyBkZWZpbmUgZ3JpZCBvcmRlcgogIG9yZGVyLnNlY3RvciA8LSBjZWxsLmxldmVsc1tjZWxsLmxldmVscyAlaW4lIGNlbGxzLnVzZV0KCiAgIyBkZWZpbmUgZ3JpZCBjb2xvcgogIGlmIChpcy5udWxsKGNvbG9yLnVzZSkpewogICAgY29sb3IudXNlID0gc2NQYWxldHRlKGxlbmd0aChjZWxsLmxldmVscykpCiAgICBuYW1lcyhjb2xvci51c2UpIDwtIGNlbGwubGV2ZWxzCiAgfSBlbHNlIGlmIChpcy5udWxsKG5hbWVzKGNvbG9yLnVzZSkpKSB7CiAgICBuYW1lcyhjb2xvci51c2UpIDwtIGNlbGwubGV2ZWxzCiAgfQogIGdyaWQuY29sIDwtIGNvbG9yLnVzZVtvcmRlci5zZWN0b3JdCiAgbmFtZXMoZ3JpZC5jb2wpIDwtIG9yZGVyLnNlY3RvcgoKICAjIHNldCBncm91cGluZyBpbmZvcm1hdGlvbgogIGlmICghaXMubnVsbChncm91cCkpIHsKICAgIGdyb3VwIDwtIGdyb3VwW25hbWVzKGdyb3VwKSAlaW4lIG9yZGVyLnNlY3Rvcl0KICB9CgogICMgZGVmaW5lIGVkZ2UgY29sb3IKICBlZGdlLmNvbG9yIDwtIGNvbG9yLnVzZVthcy5jaGFyYWN0ZXIoZGYkc291cmNlKV0KCiAgaWYgKGRpcmVjdGlvbmFsID09IDAgfCBkaXJlY3Rpb25hbCA9PSAyKSB7CiAgICBsaW5rLmFyci50eXBlID0gInRyaWFuZ2xlIgogIH0gZWxzZSB7CiAgICBsaW5rLmFyci50eXBlID0gImJpZy5hcnJvdyIKICB9CgogIGNpcmNvcy5jbGVhcigpCiAgY2hvcmREaWFncmFtKGRmLAogICAgICAgICAgICAgICBvcmRlciA9IG9yZGVyLnNlY3RvciwKICAgICAgICAgICAgICAgY29sID0gZWRnZS5jb2xvciwKICAgICAgICAgICAgICAgZ3JpZC5jb2wgPSBncmlkLmNvbCwKICAgICAgICAgICAgICAgdHJhbnNwYXJlbmN5ID0gdHJhbnNwYXJlbmN5LAogICAgICAgICAgICAgICBsaW5rLmJvcmRlciA9IGxpbmsuYm9yZGVyLAogICAgICAgICAgICAgICBkaXJlY3Rpb25hbCA9IGRpcmVjdGlvbmFsLAogICAgICAgICAgICAgICBkaXJlY3Rpb24udHlwZSA9IGMoImRpZmZIZWlnaHQiLCJhcnJvd3MiKSwKICAgICAgICAgICAgICAgbGluay5hcnIudHlwZSA9IGxpbmsuYXJyLnR5cGUsICMgbGluay5ib3JkZXIgPSAid2hpdGUiLAogICAgICAgICAgICAgICBhbm5vdGF0aW9uVHJhY2sgPSAiZ3JpZCIsCiAgICAgICAgICAgICAgIGFubm90YXRpb25UcmFja0hlaWdodCA9IGFubm90YXRpb25UcmFja0hlaWdodCwKICAgICAgICAgICAgICAgcHJlQWxsb2NhdGVUcmFja3MgPSBsaXN0KHRyYWNrLmhlaWdodCA9IG1heChzdHJ3aWR0aChvcmRlci5zZWN0b3IpKSksCiAgICAgICAgICAgICAgIHNtYWxsLmdhcCA9IHNtYWxsLmdhcCwKICAgICAgICAgICAgICAgYmlnLmdhcCA9IGJpZy5nYXAsCiAgICAgICAgICAgICAgIGxpbmsudmlzaWJsZSA9IGxpbmsudmlzaWJsZSwKICAgICAgICAgICAgICAgc2NhbGUgPSBzY2FsZSwKICAgICAgICAgICAgICAgZ3JvdXAgPSBncm91cCwKICAgICAgICAgICAgICAgbGluay50YXJnZXQucHJvcCA9IGxpbmsudGFyZ2V0LnByb3AsCiAgICAgICAgICAgICAgIHJlZHVjZSA9IHJlZHVjZSwKICAgICAgICAgICAgICAgLi4uKQogIGNpcmNvcy50cmFjayh0cmFjay5pbmRleCA9IDEsIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHgsIHkpIHsKICAgIHhsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhsaW0iKQogICAgeHBsb3QgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhwbG90IikKICAgIHlsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInlsaW0iKQogICAgc2VjdG9yLm5hbWUgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInNlY3Rvci5pbmRleCIpCiAgICBjaXJjb3MudGV4dChtZWFuKHhsaW0pLCB5bGltWzFdLCBzZWN0b3IubmFtZSwgZmFjaW5nID0gImJlbmRpbmciLCBuaWNlRmFjaW5nID0gVFJVRSwgYWRqID0gYygwLCAwLjUpLGNleCA9IGxhYi5jZXgpCiAgfSwgYmcuYm9yZGVyID0gTkEpCgogICMgaHR0cHM6Ly9qb2tlcmdvby5naXRodWIuaW8vY2lyY2xpemVfYm9vay9ib29rL2xlZ2VuZHMuaHRtbAogIGlmIChzaG93LmxlZ2VuZCkgewogICAgbGdkIDwtIENvbXBsZXhIZWF0bWFwOjpMZWdlbmQoYXQgPSBuYW1lcyhncmlkLmNvbCksIHR5cGUgPSAiZ3JpZCIsIGxlZ2VuZF9ncCA9IGdyaWQ6OmdwYXIoZmlsbCA9IGdyaWQuY29sKSwgdGl0bGUgPSAiQ2VsbCBTdGF0ZSIpCiAgICBDb21wbGV4SGVhdG1hcDo6ZHJhdyhsZ2QsIHggPSB1bml0KDEsICJucGMiKS11bml0KGxlZ2VuZC5wb3MueCwgIm1tIiksIHkgPSB1bml0KGxlZ2VuZC5wb3MueSwgIm1tIiksIGp1c3QgPSBjKCJyaWdodCIsICJib3R0b20iKSkKICB9CgogIGlmKCFpcy5udWxsKHRpdGxlLm5hbWUpKXsKICAgICMgdGl0bGUodGl0bGUubmFtZSwgY2V4ID0gMSkKICAgIHRleHQoLTAsIDEuMDIsIHRpdGxlLm5hbWUsIGNleD0xKQogIH0KICBjaXJjb3MuY2xlYXIoKQogIGdnIDwtIHJlY29yZFBsb3QoKQogIHJldHVybihnZykKfQoKYGBgCgoKCgoKCgpgYGB7cn0KbmV0VmlzdWFsX2Nob3JkX2dlbmUgPC0gZnVuY3Rpb24ob2JqZWN0LCBzbG90Lm5hbWUgPSAibmV0IiwgY29sb3IudXNlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmFsaW5nID0gTlVMTCwgcGFpckxSLnVzZSA9IE5VTEwsIG5ldCA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZXMudXNlID0gTlVMTCwgdGFyZ2V0cy51c2UgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuY2V4ID0gMC44LHNtYWxsLmdhcCA9IDEsIGJpZy5nYXAgPSAxMCwgYW5ub3RhdGlvblRyYWNrSGVpZ2h0ID0gYygwLjAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluay52aXNpYmxlID0gVFJVRSwgc2NhbGUgPSBGQUxTRSwgZGlyZWN0aW9uYWwgPSAxLCBsaW5rLnRhcmdldC5wcm9wID0gVFJVRSwgcmVkdWNlID0gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zcGFyZW5jeSA9IDAuNCwgbGluay5ib3JkZXIgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUubmFtZSA9IE5VTEwsIGxlZ2VuZC5wb3MueCA9IDIwLCBsZWdlbmQucG9zLnkgPSAyMCwgc2hvdy5sZWdlbmQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJlc2ggPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4pewogIGlmICghaXMubnVsbChwYWlyTFIudXNlKSkgewogICAgaWYgKCFpcy5kYXRhLmZyYW1lKHBhaXJMUi51c2UpKSB7CiAgICAgIHN0b3AoInBhaXJMUi51c2Ugc2hvdWxkIGJlIGEgZGF0YSBmcmFtZSB3aXRoIGEgc2lnbmxlIGNvbHVtbiBuYW1lZCBlaXRoZXIgJ2ludGVyYWN0aW9uX25hbWUnIG9yICdwYXRod2F5X25hbWUnICIpCiAgICB9IGVsc2UgaWYgKCJwYXRod2F5X25hbWUiICVpbiUgY29sbmFtZXMocGFpckxSLnVzZSkpIHsKICAgICAgbWVzc2FnZSgic2xvdC5uYW1lIGlzIHNldCB0byBiZSAnbmV0UCcgd2hlbiBwYWlyTFIudXNlIGNvbnRhaW5zIHNpZ25hbGluZyBwYXRod2F5cyIpCiAgICAgIHNsb3QubmFtZSA9ICJuZXRQIgogICAgfQogIH0KCiAgaWYgKCFpcy5udWxsKHBhaXJMUi51c2UpICYgIWlzLm51bGwoc2lnbmFsaW5nKSkgewogICAgc3RvcCgiUGxlYXNlIGRvIG5vdCBhc3NpZ24gdmFsdWVzIHRvICdzaWduYWxpbmcnIHdoZW4gdXNpbmcgJ3BhaXJMUi51c2UnIikKICB9CgogIGlmIChpcy5udWxsKG5ldCkpIHsKICAgIHByb2IgPC0gc2xvdChvYmplY3QsICJuZXQiKSRwcm9iCiAgICBwdmFsIDwtIHNsb3Qob2JqZWN0LCAibmV0IikkcHZhbAogICAgcHJvYltwdmFsID4gdGhyZXNoXSA8LSAwCiAgICBuZXQgPC0gcmVzaGFwZTI6Om1lbHQocHJvYiwgdmFsdWUubmFtZSA9ICJwcm9iIikKICAgIGNvbG5hbWVzKG5ldClbMTozXSA8LSBjKCJzb3VyY2UiLCJ0YXJnZXQiLCJpbnRlcmFjdGlvbl9uYW1lIikKCiAgICBwYWlyTFIgPSBkcGx5cjo6c2VsZWN0KG9iamVjdEBMUiRMUnNpZywgYygiaW50ZXJhY3Rpb25fbmFtZV8yIiwgInBhdGh3YXlfbmFtZSIsICAibGlnYW5kIiwgICJyZWNlcHRvciIgLCJhbm5vdGF0aW9uIiwiZXZpZGVuY2UiKSkKICAgIGlkeCA8LSBtYXRjaChuZXQkaW50ZXJhY3Rpb25fbmFtZSwgcm93bmFtZXMocGFpckxSKSkKICAgIHRlbXAgPC0gcGFpckxSW2lkeCxdCiAgICBuZXQgPC0gY2JpbmQobmV0LCB0ZW1wKQogIH0KCiAgaWYgKCFpcy5udWxsKHNpZ25hbGluZykpIHsKICAgIHBhaXJMUi51c2UgPC0gZGF0YS5mcmFtZSgpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgoc2lnbmFsaW5nKSkgewogICAgICBwYWlyTFIudXNlLmkgPC0gc2VhcmNoUGFpcihzaWduYWxpbmcgPSBzaWduYWxpbmdbaV0sIHBhaXJMUi51c2UgPSBvYmplY3RATFIkTFJzaWcsIGtleSA9ICJwYXRod2F5X25hbWUiLCBtYXRjaGluZy5leGFjdCA9IFQsIHBhaXIub25seSA9IFQpCiAgICAgIHBhaXJMUi51c2UgPC0gcmJpbmQocGFpckxSLnVzZSwgcGFpckxSLnVzZS5pKQogICAgfQogIH0KCiAgaWYgKCFpcy5udWxsKHBhaXJMUi51c2UpKXsKICAgIGlmICgiaW50ZXJhY3Rpb25fbmFtZSIgJWluJSBjb2xuYW1lcyhwYWlyTFIudXNlKSkgewogICAgICBuZXQgPC0gc3Vic2V0KG5ldCxpbnRlcmFjdGlvbl9uYW1lICVpbiUgcGFpckxSLnVzZSRpbnRlcmFjdGlvbl9uYW1lKQogICAgfSBlbHNlIGlmICgicGF0aHdheV9uYW1lIiAlaW4lIGNvbG5hbWVzKHBhaXJMUi51c2UpKSB7CiAgICAgIG5ldCA8LSBzdWJzZXQobmV0LCBwYXRod2F5X25hbWUgJWluJSBhcy5jaGFyYWN0ZXIocGFpckxSLnVzZSRwYXRod2F5X25hbWUpKQogICAgfQogIH0KCiAgaWYgKHNsb3QubmFtZSA9PSAibmV0UCIpIHsKICAgIG5ldCA8LSBkcGx5cjo6c2VsZWN0KG5ldCwgYygic291cmNlIiwidGFyZ2V0IiwicGF0aHdheV9uYW1lIiwicHJvYiIpKQogICAgbmV0JHNvdXJjZV90YXJnZXQgPC0gcGFzdGUobmV0JHNvdXJjZSwgbmV0JHRhcmdldCwgc2VwID0gInNvdXJjZVRvdGFyZ2V0IikKICAgIG5ldCA8LSBuZXQgJT4lIGRwbHlyOjpncm91cF9ieShzb3VyY2VfdGFyZ2V0LCBwYXRod2F5X25hbWUpICU+JSBkcGx5cjo6c3VtbWFyaXplKHByb2IgPSBzdW0ocHJvYikpCiAgICBhIDwtIHN0cmluZ3I6OnN0cl9zcGxpdChuZXQkc291cmNlX3RhcmdldCwgInNvdXJjZVRvdGFyZ2V0Iiwgc2ltcGxpZnkgPSBUKQogICAgbmV0JHNvdXJjZSA8LSBhcy5jaGFyYWN0ZXIoYVssIDFdKQogICAgbmV0JHRhcmdldCA8LSBhcy5jaGFyYWN0ZXIoYVssIDJdKQogICAgbmV0JGxpZ2FuZCA8LSBuZXQkcGF0aHdheV9uYW1lCiAgICBuZXQkcmVjZXB0b3IgPC0gIiAiCiAgfQoKICAjIGtlZXAgdGhlIGludGVyYWN0aW9ucyBhc3NvY2lhdGVkIHdpdGggc291cmNlcyBhbmQgdGFyZ2V0cyBvZiBpbnRlcmVzdAogIGlmICghaXMubnVsbChzb3VyY2VzLnVzZSkpewogICAgaWYgKGlzLm51bWVyaWMoc291cmNlcy51c2UpKSB7CiAgICAgIHNvdXJjZXMudXNlIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKVtzb3VyY2VzLnVzZV0KICAgIH0KICAgIG5ldCA8LSBzdWJzZXQobmV0LCBzb3VyY2UgJWluJSBzb3VyY2VzLnVzZSkKICB9IGVsc2UgewogICAgc291cmNlcy51c2UgPC0gbGV2ZWxzKG9iamVjdEBpZGVudHMpCiAgfQogIGlmICghaXMubnVsbCh0YXJnZXRzLnVzZSkpewogICAgaWYgKGlzLm51bWVyaWModGFyZ2V0cy51c2UpKSB7CiAgICAgIHRhcmdldHMudXNlIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKVt0YXJnZXRzLnVzZV0KICAgIH0KICAgIG5ldCA8LSBzdWJzZXQobmV0LCB0YXJnZXQgJWluJSB0YXJnZXRzLnVzZSkKICB9IGVsc2UgewogICAgdGFyZ2V0cy51c2UgPC0gbGV2ZWxzKG9iamVjdEBpZGVudHMpCiAgfQogICMgcmVtb3ZlIHRoZSBpbnRlcmFjdGlvbnMgd2l0aCB6ZXJvIHZhbHVlcwogIGRmIDwtIHN1YnNldChuZXQsIHByb2IgPiAwKQoKICBpZiAobnJvdyhkZikgPT0gMCkgewogICAgc3RvcCgiTm8gc2lnbmFsaW5nIGxpbmtzIGFyZSBpbmZlcnJlZCEgIikKICB9CgogIGlmIChsZW5ndGgodW5pcXVlKG5ldCRsaWdhbmQpKSA9PSAxKSB7CiAgICBtZXNzYWdlKCJZb3UgbWF5IHRyeSB0aGUgZnVuY3Rpb24gYG5ldFZpc3VhbF9jaG9yZF9jZWxsYCBmb3IgdmlzdWFsaXppbmcgaW5kaXZpZHVhbCBzaWduYWxpbmcgcGF0aHdheSIpCiAgfQoKICBkZiRpZCA8LSAxOm5yb3coZGYpCiAgIyBkZWFsIHdpdGggZHVwbGljYXRlZCBzZWN0b3IgbmFtZXMKICBsaWdhbmQudW5pIDwtIHVuaXF1ZShkZiRsaWdhbmQpCiAgZm9yIChpIGluIDE6bGVuZ3RoKGxpZ2FuZC51bmkpKSB7CiAgICBkZi5pIDwtIGRmW2RmJGxpZ2FuZCA9PSBsaWdhbmQudW5pW2ldLCBdCiAgICBzb3VyY2UudW5pIDwtIHVuaXF1ZShkZi5pJHNvdXJjZSkKICAgIGZvciAoaiBpbiAxOmxlbmd0aChzb3VyY2UudW5pKSkgewogICAgICBkZi5pLmogPC0gZGYuaVtkZi5pJHNvdXJjZSA9PSBzb3VyY2UudW5pW2pdLCBdCiAgICAgIGRmLmkuaiRsaWdhbmQgPC0gcGFzdGUwKGRmLmkuaiRsaWdhbmQsIHBhc3RlKHJlcCgnICcsai0xKSxjb2xsYXBzZSA9ICcnKSkKICAgICAgZGYkbGlnYW5kW2RmJGlkICVpbiUgZGYuaS5qJGlkXSA8LSBkZi5pLmokbGlnYW5kCiAgICB9CiAgfQogIHJlY2VwdG9yLnVuaSA8LSB1bmlxdWUoZGYkcmVjZXB0b3IpCiAgZm9yIChpIGluIDE6bGVuZ3RoKHJlY2VwdG9yLnVuaSkpIHsKICAgIGRmLmkgPC0gZGZbZGYkcmVjZXB0b3IgPT0gcmVjZXB0b3IudW5pW2ldLCBdCiAgICB0YXJnZXQudW5pIDwtIHVuaXF1ZShkZi5pJHRhcmdldCkKICAgIGZvciAoaiBpbiAxOmxlbmd0aCh0YXJnZXQudW5pKSkgewogICAgICBkZi5pLmogPC0gZGYuaVtkZi5pJHRhcmdldCA9PSB0YXJnZXQudW5pW2pdLCBdCiAgICAgIGRmLmkuaiRyZWNlcHRvciA8LSBwYXN0ZTAoZGYuaS5qJHJlY2VwdG9yLCBwYXN0ZShyZXAoJyAnLGotMSksY29sbGFwc2UgPSAnJykpCiAgICAgIGRmJHJlY2VwdG9yW2RmJGlkICVpbiUgZGYuaS5qJGlkXSA8LSBkZi5pLmokcmVjZXB0b3IKICAgIH0KICB9CgogIGNlbGwub3JkZXIuc291cmNlcyA8LSBsZXZlbHMob2JqZWN0QGlkZW50cylbbGV2ZWxzKG9iamVjdEBpZGVudHMpICVpbiUgc291cmNlcy51c2VdCiAgY2VsbC5vcmRlci50YXJnZXRzIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKVtsZXZlbHMob2JqZWN0QGlkZW50cykgJWluJSB0YXJnZXRzLnVzZV0KCiAgZGYkc291cmNlIDwtIGZhY3RvcihkZiRzb3VyY2UsIGxldmVscyA9IGNlbGwub3JkZXIuc291cmNlcykKICBkZiR0YXJnZXQgPC0gZmFjdG9yKGRmJHRhcmdldCwgbGV2ZWxzID0gY2VsbC5vcmRlci50YXJnZXRzKQogICMgZGYub3JkZXJlZC5zb3VyY2UgPC0gZGZbd2l0aChkZiwgb3JkZXIoc291cmNlLCB0YXJnZXQsIC1wcm9iKSksIF0KICAjIGRmLm9yZGVyZWQudGFyZ2V0IDwtIGRmW3dpdGgoZGYsIG9yZGVyKHRhcmdldCwgc291cmNlLCAtcHJvYikpLCBdCiAgZGYub3JkZXJlZC5zb3VyY2UgPC0gZGZbd2l0aChkZiwgb3JkZXIoc291cmNlLCAtcHJvYikpLCBdCiAgZGYub3JkZXJlZC50YXJnZXQgPC0gZGZbd2l0aChkZiwgb3JkZXIodGFyZ2V0LCAtcHJvYikpLCBdCgogIG9yZGVyLnNvdXJjZSA8LSB1bmlxdWUoZGYub3JkZXJlZC5zb3VyY2VbICxjKCdsaWdhbmQnLCdzb3VyY2UnKV0pCiAgb3JkZXIudGFyZ2V0IDwtIHVuaXF1ZShkZi5vcmRlcmVkLnRhcmdldFsgLGMoJ3JlY2VwdG9yJywndGFyZ2V0JyldKQoKICAjIGRlZmluZSBzZWN0b3Igb3JkZXIKICBvcmRlci5zZWN0b3IgPC0gYyhvcmRlci5zb3VyY2UkbGlnYW5kLCBvcmRlci50YXJnZXQkcmVjZXB0b3IpCgogICMgZGVmaW5lIGNlbGwgdHlwZSBjb2xvcgogIGlmIChpcy5udWxsKGNvbG9yLnVzZSkpewogICAgY29sb3IudXNlID0gc2NQYWxldHRlKG5sZXZlbHMob2JqZWN0QGlkZW50cykpCiAgICBuYW1lcyhjb2xvci51c2UpIDwtIGxldmVscyhvYmplY3RAaWRlbnRzKQogICAgY29sb3IudXNlIDwtIGNvbG9yLnVzZVtsZXZlbHMob2JqZWN0QGlkZW50cykgJWluJSBhcy5jaGFyYWN0ZXIodW5pb24oZGYkc291cmNlLGRmJHRhcmdldCkpXQogIH0gZWxzZSBpZiAoaXMubnVsbChuYW1lcyhjb2xvci51c2UpKSkgewogICAgbmFtZXMoY29sb3IudXNlKSA8LSBsZXZlbHMob2JqZWN0QGlkZW50cykKICAgIGNvbG9yLnVzZSA8LSBjb2xvci51c2VbbGV2ZWxzKG9iamVjdEBpZGVudHMpICVpbiUgYXMuY2hhcmFjdGVyKHVuaW9uKGRmJHNvdXJjZSxkZiR0YXJnZXQpKV0KICB9CgogICMgZGVmaW5lIGVkZ2UgY29sb3IKICBlZGdlLmNvbG9yIDwtIGNvbG9yLnVzZVthcy5jaGFyYWN0ZXIoZGYub3JkZXJlZC5zb3VyY2Ukc291cmNlKV0KICBuYW1lcyhlZGdlLmNvbG9yKSA8LSBhcy5jaGFyYWN0ZXIoZGYub3JkZXJlZC5zb3VyY2Ukc291cmNlKQoKICAjIGRlZmluZSBncmlkIGNvbG9ycwogIGdyaWQuY29sLmxpZ2FuZCA8LSBjb2xvci51c2VbYXMuY2hhcmFjdGVyKG9yZGVyLnNvdXJjZSRzb3VyY2UpXQogIG5hbWVzKGdyaWQuY29sLmxpZ2FuZCkgPC0gYXMuY2hhcmFjdGVyKG9yZGVyLnNvdXJjZSRzb3VyY2UpCiAgZ3JpZC5jb2wucmVjZXB0b3IgPC0gY29sb3IudXNlW2FzLmNoYXJhY3RlcihvcmRlci50YXJnZXQkdGFyZ2V0KV0KICBuYW1lcyhncmlkLmNvbC5yZWNlcHRvcikgPC0gYXMuY2hhcmFjdGVyKG9yZGVyLnRhcmdldCR0YXJnZXQpCiAgZ3JpZC5jb2wgPC0gYyhhcy5jaGFyYWN0ZXIoZ3JpZC5jb2wubGlnYW5kKSwgYXMuY2hhcmFjdGVyKGdyaWQuY29sLnJlY2VwdG9yKSkKICBuYW1lcyhncmlkLmNvbCkgPC0gb3JkZXIuc2VjdG9yCgogIGRmLnBsb3QgPC0gZGYub3JkZXJlZC5zb3VyY2VbICxjKCdsaWdhbmQnLCdyZWNlcHRvcicsJ3Byb2InKV0KCiAgaWYgKGRpcmVjdGlvbmFsID09IDIpIHsKICAgIGxpbmsuYXJyLnR5cGUgPSAidHJpYW5nbGUiCiAgfSBlbHNlIHsKICAgIGxpbmsuYXJyLnR5cGUgPSAiYmlnLmFycm93IgogIH0KICBjaXJjb3MuY2xlYXIoKQogIGNob3JkRGlhZ3JhbShkZi5wbG90LAogICAgICAgICAgICAgICBvcmRlciA9IG9yZGVyLnNlY3RvciwKICAgICAgICAgICAgICAgY29sID0gZWRnZS5jb2xvciwKICAgICAgICAgICAgICAgZ3JpZC5jb2wgPSBncmlkLmNvbCwKICAgICAgICAgICAgICAgdHJhbnNwYXJlbmN5ID0gdHJhbnNwYXJlbmN5LAogICAgICAgICAgICAgICBsaW5rLmJvcmRlciA9IGxpbmsuYm9yZGVyLAogICAgICAgICAgICAgICBkaXJlY3Rpb25hbCA9IGRpcmVjdGlvbmFsLAogICAgICAgICAgICAgICBkaXJlY3Rpb24udHlwZSA9IGMoImRpZmZIZWlnaHQiLCJhcnJvd3MiKSwKICAgICAgICAgICAgICAgbGluay5hcnIudHlwZSA9IGxpbmsuYXJyLnR5cGUsCiAgICAgICAgICAgICAgIGFubm90YXRpb25UcmFjayA9ICJncmlkIiwKICAgICAgICAgICAgICAgYW5ub3RhdGlvblRyYWNrSGVpZ2h0ID0gYW5ub3RhdGlvblRyYWNrSGVpZ2h0LAogICAgICAgICAgICAgICBwcmVBbGxvY2F0ZVRyYWNrcyA9IGxpc3QodHJhY2suaGVpZ2h0ID0gbWF4KHN0cndpZHRoKG9yZGVyLnNlY3RvcikpKSwKICAgICAgICAgICAgICAgc21hbGwuZ2FwID0gc21hbGwuZ2FwLAogICAgICAgICAgICAgICBiaWcuZ2FwID0gYmlnLmdhcCwKICAgICAgICAgICAgICAgbGluay52aXNpYmxlID0gbGluay52aXNpYmxlLAogICAgICAgICAgICAgICBzY2FsZSA9IHNjYWxlLAogICAgICAgICAgICAgICBsaW5rLnRhcmdldC5wcm9wID0gbGluay50YXJnZXQucHJvcCwKICAgICAgICAgICAgICAgcmVkdWNlID0gcmVkdWNlLAogICAgICAgICAgICAgICAuLi4pCgogIGNpcmNvcy50cmFjayh0cmFjay5pbmRleCA9IDEsIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHgsIHkpIHsKICAgIHhsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhsaW0iKQogICAgeHBsb3QgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhwbG90IikKICAgIHlsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInlsaW0iKQogICAgc2VjdG9yLm5hbWUgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInNlY3Rvci5pbmRleCIpCiAgICBjaXJjb3MudGV4dChtZWFuKHhsaW0pLCB5bGltWzFdLCBzZWN0b3IubmFtZSwgZmFjaW5nID0gImJlbmRpbmciLCBuaWNlRmFjaW5nID0gVFJVRSwgYWRqPWMoMC41LDAuMDEpLGNleCA9IGxhYi5jZXgpCiAgfSwgYmcuYm9yZGVyID0gTkEpCgoKICAjIGh0dHBzOi8vam9rZXJnb28uZ2l0aHViLmlvL2NpcmNsaXplX2Jvb2svYm9vay9sZWdlbmRzLmh0bWwKICBpZiAoc2hvdy5sZWdlbmQpIHsKICAgIGxnZCA8LSBDb21wbGV4SGVhdG1hcDo6TGVnZW5kKGF0ID0gbmFtZXMoY29sb3IudXNlKSwgdHlwZSA9ICJncmlkIiwgbGVnZW5kX2dwID0gZ3JpZDo6Z3BhcihmaWxsID0gY29sb3IudXNlKSwgdGl0bGUgPSAiQ2VsbCBTdGF0ZSIpCiAgICBDb21wbGV4SGVhdG1hcDo6ZHJhdyhsZ2QsIHggPSB1bml0KDEsICJucGMiKS11bml0KGxlZ2VuZC5wb3MueCwgIm1tIiksIHkgPSB1bml0KGxlZ2VuZC5wb3MueSwgIm1tIiksIGp1c3QgPSBjKCJyaWdodCIsICJib3R0b20iKSkKICB9CgogIGNpcmNvcy5jbGVhcigpCiAgaWYoIWlzLm51bGwodGl0bGUubmFtZSkpewogICAgdGV4dCgtMCwgMS4wMiwgdGl0bGUubmFtZSwgY2V4PTEpCiAgfQogIGdnIDwtIHJlY29yZFBsb3QoKQogIHJldHVybihnZykKfQpgYGAKCgpgYGB7cn0KbmV0VmlzdWFsX2Nob3JkX2dlbmUoY2VsbGNoYXQsIHNpZ25hbGluZyA9IGMoIkNDTCIpLCAKICAgICAgICAgICAgICAgICAgICAgI3NvdXJjZXMudXNlID0gYygxLDIsMyw1LDYsNyw4KSwgdGFyZ2V0cy51c2UgPSBjKDEsMiwzLDUsNiw3LDgpLCAKbGVnZW5kLnBvcy54ID0gOCxzY2FsZT1UUlVFLCBjb2xvci51c2UgPSBjKCcjQ0Q2NjAwJywgJyNGRjhDMDAnLCAnI0NEMDBDRCcsICMnIzM4OEU4RScsIAonIzgwMDA3YycsICcjOEZCQzhGJywgJyNDMUZGQzEnLCAnIzIyOEIyMicpLGxhYi5jZXggPSAwLjgpIApgYGAKCgpgYGB7cn0KYSA8LSBuZXRWaXN1YWxfY2hvcmRfZ2VuZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gYygiQ0NMIiksIAogICAgICAgICAgICAgICAgICAgICAjc291cmNlcy51c2UgPSBjKDEsMiwzLDUsNiw3LDgpLCB0YXJnZXRzLnVzZSA9IGMoMSwyLDMsNSw2LDcsOCksIApsZWdlbmQucG9zLnggPSA4LHNjYWxlPVRSVUUsIGNvbG9yLnVzZSA9IGMoJyNDRDY2MDAnLCAnI0ZGOEMwMCcsICcjQ0QwMENEJywgIycjMzg4RThFJywgCicjQkY4RkFGJywgJyM4RkJDOEYnLCAnI0MxRkZDMScsICcjMjI4QjIyJyksbGFiLmNleCA9IDEpIApgYGAKCgoKYGBge3J9CmpwZWcoImZpbmFsX2ZpZ3VyZXMvQ1hDTF9jaG9yZC5qcGVnIix3aWR0aD0zMCxoZWlnaHQ9MzAsdW5pdHM9ImNtIixxdWFsaXR5PTEwMCxyZXM9MzAwKQpuZXRWaXN1YWxfY2hvcmRfZ2VuZShjZWxsY2hhdCwgc2lnbmFsaW5nID0gYygiQ1hDTCIpLCAKICAgICAgICAgICAgICAgICAgICAgI3NvdXJjZXMudXNlID0gYygxLDIsMyw1LDYsNyw4KSwgdGFyZ2V0cy51c2UgPSBjKDEsMiwzLDUsNiw3LDgpLCAKbGVnZW5kLnBvcy54ID0gOCxzY2FsZT1UUlVFLCBjb2xvci51c2UgPSBjKCcjQ0Q2NjAwJywgJyNGRjhDMDAnLCAnI0NEMDBDRCcsICMnIzM4OEU4RScsIAonI0JDOEY4RicsICcjOEZCQzhGJywgJyNDMUZGQzEnLCAnIzIyOEIyMicpLGxhYi5jZXggPSAzKSAKZGV2Lm9mZigpCmBgYAoKCg==